gitx.do 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -353
- package/dist/do/logger.d.ts +50 -0
- package/dist/do/logger.d.ts.map +1 -0
- package/dist/do/logger.js +122 -0
- package/dist/do/logger.js.map +1 -0
- package/dist/{durable-object → do}/schema.d.ts +3 -3
- package/dist/do/schema.d.ts.map +1 -0
- package/dist/{durable-object → do}/schema.js +4 -3
- package/dist/do/schema.js.map +1 -0
- package/dist/do/types.d.ts +267 -0
- package/dist/do/types.d.ts.map +1 -0
- package/dist/do/types.js +62 -0
- package/dist/do/types.js.map +1 -0
- package/dist/index.d.ts +15 -469
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -481
- package/dist/index.js.map +1 -1
- package/dist/mcp/auth.d.ts +77 -0
- package/dist/mcp/auth.d.ts.map +1 -0
- package/dist/mcp/auth.js +278 -0
- package/dist/mcp/auth.js.map +1 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +19 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +200 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +275 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tool-registry.d.ts +47 -0
- package/dist/mcp/tool-registry.d.ts.map +1 -0
- package/dist/mcp/tool-registry.js +284 -0
- package/dist/mcp/tool-registry.js.map +1 -0
- package/dist/mcp/tools.d.ts +103 -515
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +676 -3087
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/types.d.ts +124 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +9 -0
- package/dist/mcp/types.js.map +1 -0
- package/package.json +19 -21
- package/dist/cli/commands/add.d.ts +0 -176
- package/dist/cli/commands/add.d.ts.map +0 -1
- package/dist/cli/commands/add.js +0 -979
- package/dist/cli/commands/add.js.map +0 -1
- package/dist/cli/commands/blame.d.ts +0 -259
- package/dist/cli/commands/blame.d.ts.map +0 -1
- package/dist/cli/commands/blame.js +0 -609
- package/dist/cli/commands/blame.js.map +0 -1
- package/dist/cli/commands/branch.d.ts +0 -249
- package/dist/cli/commands/branch.d.ts.map +0 -1
- package/dist/cli/commands/branch.js +0 -693
- package/dist/cli/commands/branch.js.map +0 -1
- package/dist/cli/commands/checkout.d.ts +0 -73
- package/dist/cli/commands/checkout.d.ts.map +0 -1
- package/dist/cli/commands/checkout.js +0 -725
- package/dist/cli/commands/checkout.js.map +0 -1
- package/dist/cli/commands/commit.d.ts +0 -182
- package/dist/cli/commands/commit.d.ts.map +0 -1
- package/dist/cli/commands/commit.js +0 -457
- package/dist/cli/commands/commit.js.map +0 -1
- package/dist/cli/commands/diff.d.ts +0 -464
- package/dist/cli/commands/diff.d.ts.map +0 -1
- package/dist/cli/commands/diff.js +0 -959
- package/dist/cli/commands/diff.js.map +0 -1
- package/dist/cli/commands/log.d.ts +0 -239
- package/dist/cli/commands/log.d.ts.map +0 -1
- package/dist/cli/commands/log.js +0 -535
- package/dist/cli/commands/log.js.map +0 -1
- package/dist/cli/commands/merge.d.ts +0 -106
- package/dist/cli/commands/merge.d.ts.map +0 -1
- package/dist/cli/commands/merge.js +0 -852
- package/dist/cli/commands/merge.js.map +0 -1
- package/dist/cli/commands/review.d.ts +0 -457
- package/dist/cli/commands/review.d.ts.map +0 -1
- package/dist/cli/commands/review.js +0 -558
- package/dist/cli/commands/review.js.map +0 -1
- package/dist/cli/commands/stash.d.ts +0 -157
- package/dist/cli/commands/stash.d.ts.map +0 -1
- package/dist/cli/commands/stash.js +0 -655
- package/dist/cli/commands/stash.js.map +0 -1
- package/dist/cli/commands/status.d.ts +0 -269
- package/dist/cli/commands/status.d.ts.map +0 -1
- package/dist/cli/commands/status.js +0 -492
- package/dist/cli/commands/status.js.map +0 -1
- package/dist/cli/commands/web.d.ts +0 -199
- package/dist/cli/commands/web.d.ts.map +0 -1
- package/dist/cli/commands/web.js +0 -697
- package/dist/cli/commands/web.js.map +0 -1
- package/dist/cli/fs-adapter.d.ts +0 -656
- package/dist/cli/fs-adapter.d.ts.map +0 -1
- package/dist/cli/fs-adapter.js +0 -1177
- package/dist/cli/fs-adapter.js.map +0 -1
- package/dist/cli/fsx-cli-adapter.d.ts +0 -359
- package/dist/cli/fsx-cli-adapter.d.ts.map +0 -1
- package/dist/cli/fsx-cli-adapter.js +0 -619
- package/dist/cli/fsx-cli-adapter.js.map +0 -1
- package/dist/cli/index.d.ts +0 -387
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -579
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/ui/components/DiffView.d.ts +0 -12
- package/dist/cli/ui/components/DiffView.d.ts.map +0 -1
- package/dist/cli/ui/components/DiffView.js +0 -11
- package/dist/cli/ui/components/DiffView.js.map +0 -1
- package/dist/cli/ui/components/ErrorDisplay.d.ts +0 -10
- package/dist/cli/ui/components/ErrorDisplay.d.ts.map +0 -1
- package/dist/cli/ui/components/ErrorDisplay.js +0 -11
- package/dist/cli/ui/components/ErrorDisplay.js.map +0 -1
- package/dist/cli/ui/components/FuzzySearch.d.ts +0 -15
- package/dist/cli/ui/components/FuzzySearch.d.ts.map +0 -1
- package/dist/cli/ui/components/FuzzySearch.js +0 -12
- package/dist/cli/ui/components/FuzzySearch.js.map +0 -1
- package/dist/cli/ui/components/LoadingSpinner.d.ts +0 -10
- package/dist/cli/ui/components/LoadingSpinner.d.ts.map +0 -1
- package/dist/cli/ui/components/LoadingSpinner.js +0 -10
- package/dist/cli/ui/components/LoadingSpinner.js.map +0 -1
- package/dist/cli/ui/components/NavigationList.d.ts +0 -14
- package/dist/cli/ui/components/NavigationList.d.ts.map +0 -1
- package/dist/cli/ui/components/NavigationList.js +0 -11
- package/dist/cli/ui/components/NavigationList.js.map +0 -1
- package/dist/cli/ui/components/ScrollableContent.d.ts +0 -13
- package/dist/cli/ui/components/ScrollableContent.d.ts.map +0 -1
- package/dist/cli/ui/components/ScrollableContent.js +0 -11
- package/dist/cli/ui/components/ScrollableContent.js.map +0 -1
- package/dist/cli/ui/components/index.d.ts +0 -7
- package/dist/cli/ui/components/index.d.ts.map +0 -1
- package/dist/cli/ui/components/index.js +0 -9
- package/dist/cli/ui/components/index.js.map +0 -1
- package/dist/cli/ui/terminal-ui.d.ts +0 -85
- package/dist/cli/ui/terminal-ui.d.ts.map +0 -1
- package/dist/cli/ui/terminal-ui.js +0 -121
- package/dist/cli/ui/terminal-ui.js.map +0 -1
- package/dist/do/BashModule.d.ts +0 -871
- package/dist/do/BashModule.d.ts.map +0 -1
- package/dist/do/BashModule.js +0 -1143
- package/dist/do/BashModule.js.map +0 -1
- package/dist/do/FsModule.d.ts +0 -612
- package/dist/do/FsModule.d.ts.map +0 -1
- package/dist/do/FsModule.js +0 -1120
- package/dist/do/FsModule.js.map +0 -1
- package/dist/do/GitModule.d.ts +0 -635
- package/dist/do/GitModule.d.ts.map +0 -1
- package/dist/do/GitModule.js +0 -784
- package/dist/do/GitModule.js.map +0 -1
- package/dist/do/GitRepoDO.d.ts +0 -281
- package/dist/do/GitRepoDO.d.ts.map +0 -1
- package/dist/do/GitRepoDO.js +0 -479
- package/dist/do/GitRepoDO.js.map +0 -1
- package/dist/do/bash-ast.d.ts +0 -246
- package/dist/do/bash-ast.d.ts.map +0 -1
- package/dist/do/bash-ast.js +0 -888
- package/dist/do/bash-ast.js.map +0 -1
- package/dist/do/container-executor.d.ts +0 -491
- package/dist/do/container-executor.d.ts.map +0 -1
- package/dist/do/container-executor.js +0 -731
- package/dist/do/container-executor.js.map +0 -1
- package/dist/do/index.d.ts +0 -53
- package/dist/do/index.d.ts.map +0 -1
- package/dist/do/index.js +0 -91
- package/dist/do/index.js.map +0 -1
- package/dist/do/tiered-storage.d.ts +0 -403
- package/dist/do/tiered-storage.d.ts.map +0 -1
- package/dist/do/tiered-storage.js +0 -689
- package/dist/do/tiered-storage.js.map +0 -1
- package/dist/do/withBash.d.ts +0 -231
- package/dist/do/withBash.d.ts.map +0 -1
- package/dist/do/withBash.js +0 -244
- package/dist/do/withBash.js.map +0 -1
- package/dist/do/withFs.d.ts +0 -237
- package/dist/do/withFs.d.ts.map +0 -1
- package/dist/do/withFs.js +0 -387
- package/dist/do/withFs.js.map +0 -1
- package/dist/do/withGit.d.ts +0 -180
- package/dist/do/withGit.d.ts.map +0 -1
- package/dist/do/withGit.js +0 -271
- package/dist/do/withGit.js.map +0 -1
- package/dist/durable-object/object-store.d.ts +0 -633
- package/dist/durable-object/object-store.d.ts.map +0 -1
- package/dist/durable-object/object-store.js +0 -1164
- package/dist/durable-object/object-store.js.map +0 -1
- package/dist/durable-object/schema.d.ts.map +0 -1
- package/dist/durable-object/schema.js.map +0 -1
- package/dist/durable-object/wal.d.ts +0 -416
- package/dist/durable-object/wal.d.ts.map +0 -1
- package/dist/durable-object/wal.js +0 -445
- package/dist/durable-object/wal.js.map +0 -1
- package/dist/mcp/adapter.d.ts +0 -772
- package/dist/mcp/adapter.d.ts.map +0 -1
- package/dist/mcp/adapter.js +0 -895
- package/dist/mcp/adapter.js.map +0 -1
- package/dist/mcp/sandbox/miniflare-evaluator.d.ts +0 -22
- package/dist/mcp/sandbox/miniflare-evaluator.d.ts.map +0 -1
- package/dist/mcp/sandbox/miniflare-evaluator.js +0 -140
- package/dist/mcp/sandbox/miniflare-evaluator.js.map +0 -1
- package/dist/mcp/sandbox/object-store-proxy.d.ts +0 -32
- package/dist/mcp/sandbox/object-store-proxy.d.ts.map +0 -1
- package/dist/mcp/sandbox/object-store-proxy.js +0 -30
- package/dist/mcp/sandbox/object-store-proxy.js.map +0 -1
- package/dist/mcp/sandbox/template.d.ts +0 -17
- package/dist/mcp/sandbox/template.d.ts.map +0 -1
- package/dist/mcp/sandbox/template.js +0 -71
- package/dist/mcp/sandbox/template.js.map +0 -1
- package/dist/mcp/sandbox.d.ts +0 -764
- package/dist/mcp/sandbox.d.ts.map +0 -1
- package/dist/mcp/sandbox.js +0 -1362
- package/dist/mcp/sandbox.js.map +0 -1
- package/dist/mcp/sdk-adapter.d.ts +0 -835
- package/dist/mcp/sdk-adapter.d.ts.map +0 -1
- package/dist/mcp/sdk-adapter.js +0 -974
- package/dist/mcp/sdk-adapter.js.map +0 -1
- package/dist/mcp/tools/do.d.ts +0 -32
- package/dist/mcp/tools/do.d.ts.map +0 -1
- package/dist/mcp/tools/do.js +0 -117
- package/dist/mcp/tools/do.js.map +0 -1
- package/dist/ops/blame.d.ts +0 -551
- package/dist/ops/blame.d.ts.map +0 -1
- package/dist/ops/blame.js +0 -1037
- package/dist/ops/blame.js.map +0 -1
- package/dist/ops/branch.d.ts +0 -766
- package/dist/ops/branch.d.ts.map +0 -1
- package/dist/ops/branch.js +0 -950
- package/dist/ops/branch.js.map +0 -1
- package/dist/ops/commit-traversal.d.ts +0 -349
- package/dist/ops/commit-traversal.d.ts.map +0 -1
- package/dist/ops/commit-traversal.js +0 -821
- package/dist/ops/commit-traversal.js.map +0 -1
- package/dist/ops/commit.d.ts +0 -555
- package/dist/ops/commit.d.ts.map +0 -1
- package/dist/ops/commit.js +0 -826
- package/dist/ops/commit.js.map +0 -1
- package/dist/ops/merge-base.d.ts +0 -397
- package/dist/ops/merge-base.d.ts.map +0 -1
- package/dist/ops/merge-base.js +0 -691
- package/dist/ops/merge-base.js.map +0 -1
- package/dist/ops/merge.d.ts +0 -855
- package/dist/ops/merge.d.ts.map +0 -1
- package/dist/ops/merge.js +0 -1551
- package/dist/ops/merge.js.map +0 -1
- package/dist/ops/tag.d.ts +0 -247
- package/dist/ops/tag.d.ts.map +0 -1
- package/dist/ops/tag.js +0 -649
- package/dist/ops/tag.js.map +0 -1
- package/dist/ops/tree-builder.d.ts +0 -178
- package/dist/ops/tree-builder.d.ts.map +0 -1
- package/dist/ops/tree-builder.js +0 -271
- package/dist/ops/tree-builder.js.map +0 -1
- package/dist/ops/tree-diff.d.ts +0 -291
- package/dist/ops/tree-diff.d.ts.map +0 -1
- package/dist/ops/tree-diff.js +0 -705
- package/dist/ops/tree-diff.js.map +0 -1
- package/dist/pack/delta.d.ts +0 -248
- package/dist/pack/delta.d.ts.map +0 -1
- package/dist/pack/delta.js +0 -740
- package/dist/pack/delta.js.map +0 -1
- package/dist/pack/format.d.ts +0 -446
- package/dist/pack/format.d.ts.map +0 -1
- package/dist/pack/format.js +0 -572
- package/dist/pack/format.js.map +0 -1
- package/dist/pack/full-generation.d.ts +0 -612
- package/dist/pack/full-generation.d.ts.map +0 -1
- package/dist/pack/full-generation.js +0 -1378
- package/dist/pack/full-generation.js.map +0 -1
- package/dist/pack/generation.d.ts +0 -441
- package/dist/pack/generation.d.ts.map +0 -1
- package/dist/pack/generation.js +0 -707
- package/dist/pack/generation.js.map +0 -1
- package/dist/pack/index.d.ts +0 -502
- package/dist/pack/index.d.ts.map +0 -1
- package/dist/pack/index.js +0 -833
- package/dist/pack/index.js.map +0 -1
- package/dist/refs/branch.d.ts +0 -683
- package/dist/refs/branch.d.ts.map +0 -1
- package/dist/refs/branch.js +0 -881
- package/dist/refs/branch.js.map +0 -1
- package/dist/refs/storage.d.ts +0 -833
- package/dist/refs/storage.d.ts.map +0 -1
- package/dist/refs/storage.js +0 -1023
- package/dist/refs/storage.js.map +0 -1
- package/dist/refs/tag.d.ts +0 -860
- package/dist/refs/tag.d.ts.map +0 -1
- package/dist/refs/tag.js +0 -996
- package/dist/refs/tag.js.map +0 -1
- package/dist/storage/backend.d.ts +0 -425
- package/dist/storage/backend.d.ts.map +0 -1
- package/dist/storage/backend.js +0 -41
- package/dist/storage/backend.js.map +0 -1
- package/dist/storage/fsx-adapter.d.ts +0 -204
- package/dist/storage/fsx-adapter.d.ts.map +0 -1
- package/dist/storage/fsx-adapter.js +0 -518
- package/dist/storage/fsx-adapter.js.map +0 -1
- package/dist/storage/lru-cache.d.ts +0 -691
- package/dist/storage/lru-cache.d.ts.map +0 -1
- package/dist/storage/lru-cache.js +0 -813
- package/dist/storage/lru-cache.js.map +0 -1
- package/dist/storage/object-index.d.ts +0 -585
- package/dist/storage/object-index.d.ts.map +0 -1
- package/dist/storage/object-index.js +0 -532
- package/dist/storage/object-index.js.map +0 -1
- package/dist/storage/r2-pack.d.ts +0 -1257
- package/dist/storage/r2-pack.d.ts.map +0 -1
- package/dist/storage/r2-pack.js +0 -1773
- package/dist/storage/r2-pack.js.map +0 -1
- package/dist/tiered/cdc-pipeline.d.ts +0 -1888
- package/dist/tiered/cdc-pipeline.d.ts.map +0 -1
- package/dist/tiered/cdc-pipeline.js +0 -1880
- package/dist/tiered/cdc-pipeline.js.map +0 -1
- package/dist/tiered/migration.d.ts +0 -1104
- package/dist/tiered/migration.d.ts.map +0 -1
- package/dist/tiered/migration.js +0 -1217
- package/dist/tiered/migration.js.map +0 -1
- package/dist/tiered/parquet-writer.d.ts +0 -1145
- package/dist/tiered/parquet-writer.d.ts.map +0 -1
- package/dist/tiered/parquet-writer.js +0 -1183
- package/dist/tiered/parquet-writer.js.map +0 -1
- package/dist/tiered/read-path.d.ts +0 -835
- package/dist/tiered/read-path.d.ts.map +0 -1
- package/dist/tiered/read-path.js +0 -487
- package/dist/tiered/read-path.js.map +0 -1
- package/dist/types/capability.d.ts +0 -1385
- package/dist/types/capability.d.ts.map +0 -1
- package/dist/types/capability.js +0 -36
- package/dist/types/capability.js.map +0 -1
- package/dist/types/index.d.ts +0 -13
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -18
- package/dist/types/index.js.map +0 -1
- package/dist/types/interfaces.d.ts +0 -673
- package/dist/types/interfaces.d.ts.map +0 -1
- package/dist/types/interfaces.js +0 -26
- package/dist/types/interfaces.js.map +0 -1
- package/dist/types/objects.d.ts +0 -692
- package/dist/types/objects.d.ts.map +0 -1
- package/dist/types/objects.js +0 -837
- package/dist/types/objects.js.map +0 -1
- package/dist/types/storage.d.ts +0 -603
- package/dist/types/storage.d.ts.map +0 -1
- package/dist/types/storage.js +0 -191
- package/dist/types/storage.js.map +0 -1
- package/dist/types/worker-loader.d.ts +0 -60
- package/dist/types/worker-loader.d.ts.map +0 -1
- package/dist/types/worker-loader.js +0 -62
- package/dist/types/worker-loader.js.map +0 -1
- package/dist/utils/hash.d.ts +0 -198
- package/dist/utils/hash.d.ts.map +0 -1
- package/dist/utils/hash.js +0 -272
- package/dist/utils/hash.js.map +0 -1
- package/dist/utils/sha1.d.ts +0 -325
- package/dist/utils/sha1.d.ts.map +0 -1
- package/dist/utils/sha1.js +0 -635
- package/dist/utils/sha1.js.map +0 -1
- package/dist/wire/capabilities.d.ts +0 -1044
- package/dist/wire/capabilities.d.ts.map +0 -1
- package/dist/wire/capabilities.js +0 -941
- package/dist/wire/capabilities.js.map +0 -1
- package/dist/wire/path-security.d.ts +0 -157
- package/dist/wire/path-security.d.ts.map +0 -1
- package/dist/wire/path-security.js +0 -307
- package/dist/wire/path-security.js.map +0 -1
- package/dist/wire/pkt-line.d.ts +0 -345
- package/dist/wire/pkt-line.d.ts.map +0 -1
- package/dist/wire/pkt-line.js +0 -381
- package/dist/wire/pkt-line.js.map +0 -1
- package/dist/wire/receive-pack.d.ts +0 -1059
- package/dist/wire/receive-pack.d.ts.map +0 -1
- package/dist/wire/receive-pack.js +0 -1414
- package/dist/wire/receive-pack.js.map +0 -1
- package/dist/wire/smart-http.d.ts +0 -799
- package/dist/wire/smart-http.d.ts.map +0 -1
- package/dist/wire/smart-http.js +0 -945
- package/dist/wire/smart-http.js.map +0 -1
- package/dist/wire/upload-pack.d.ts +0 -727
- package/dist/wire/upload-pack.d.ts.map +0 -1
- package/dist/wire/upload-pack.js +0 -1141
- package/dist/wire/upload-pack.js.map +0 -1
package/dist/do/GitModule.js
DELETED
|
@@ -1,784 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview GitModule for Durable Object Integration
|
|
3
|
-
*
|
|
4
|
-
* This module provides a GitModule class that integrates with dotdo's $ WorkflowContext,
|
|
5
|
-
* providing $.git.sync(), $.git.push(), and $.git.binding functionality.
|
|
6
|
-
*
|
|
7
|
-
* The module depends on FsModule for file operations and uses R2 as the
|
|
8
|
-
* global git object store for cross-DO synchronization.
|
|
9
|
-
*
|
|
10
|
-
* @module do/GitModule
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```typescript
|
|
14
|
-
* import { GitModule } from 'gitx.do/do'
|
|
15
|
-
*
|
|
16
|
-
* class MyDO extends DO {
|
|
17
|
-
* git = new GitModule(this.$, {
|
|
18
|
-
* repo: 'org/repo',
|
|
19
|
-
* branch: 'main',
|
|
20
|
-
* r2: this.env.R2_BUCKET
|
|
21
|
-
* })
|
|
22
|
-
*
|
|
23
|
-
* async syncRepository() {
|
|
24
|
-
* await this.git.sync()
|
|
25
|
-
* const status = await this.git.status()
|
|
26
|
-
* console.log(`On branch ${status.branch}`)
|
|
27
|
-
* }
|
|
28
|
-
* }
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
// ============================================================================
|
|
32
|
-
// GitModule Class
|
|
33
|
-
// ============================================================================
|
|
34
|
-
/**
|
|
35
|
-
* GitModule class for integration with dotdo's $ WorkflowContext.
|
|
36
|
-
*
|
|
37
|
-
* @description
|
|
38
|
-
* Provides git functionality as a capability module that integrates with
|
|
39
|
-
* dotdo's Durable Object framework. The module:
|
|
40
|
-
*
|
|
41
|
-
* - Syncs git objects from R2 global object store to local storage via FsModule
|
|
42
|
-
* - Pushes local changes back to R2 for cross-DO synchronization
|
|
43
|
-
* - Provides a binding property for repository configuration
|
|
44
|
-
* - Implements standard git operations (status, add, commit)
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* ```typescript
|
|
48
|
-
* // In a Durable Object
|
|
49
|
-
* class MyDO extends DO {
|
|
50
|
-
* private git: GitModule
|
|
51
|
-
*
|
|
52
|
-
* constructor(state: DurableObjectState, env: Env) {
|
|
53
|
-
* super(state, env)
|
|
54
|
-
* this.git = new GitModule({
|
|
55
|
-
* repo: 'my-org/my-repo',
|
|
56
|
-
* branch: 'main',
|
|
57
|
-
* r2: env.GIT_OBJECTS,
|
|
58
|
-
* fs: this.$.fs
|
|
59
|
-
* })
|
|
60
|
-
* }
|
|
61
|
-
*
|
|
62
|
-
* async fetch(request: Request) {
|
|
63
|
-
* // Sync from R2
|
|
64
|
-
* await this.git.sync()
|
|
65
|
-
*
|
|
66
|
-
* // Make changes via $.fs
|
|
67
|
-
* await this.$.fs.writeFile('/src/index.ts', 'new code')
|
|
68
|
-
*
|
|
69
|
-
* // Stage and commit
|
|
70
|
-
* await this.git.add('src/index.ts')
|
|
71
|
-
* await this.git.commit('Update code')
|
|
72
|
-
*
|
|
73
|
-
* // Push to R2
|
|
74
|
-
* await this.git.push()
|
|
75
|
-
*
|
|
76
|
-
* return new Response('OK')
|
|
77
|
-
* }
|
|
78
|
-
* }
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
|
-
export class GitModule {
|
|
82
|
-
/**
|
|
83
|
-
* Capability module name for identification.
|
|
84
|
-
*/
|
|
85
|
-
name = 'git';
|
|
86
|
-
/**
|
|
87
|
-
* Repository identifier.
|
|
88
|
-
*/
|
|
89
|
-
repo;
|
|
90
|
-
/**
|
|
91
|
-
* Branch being tracked.
|
|
92
|
-
*/
|
|
93
|
-
branch;
|
|
94
|
-
/**
|
|
95
|
-
* Path prefix within the repository.
|
|
96
|
-
*/
|
|
97
|
-
path;
|
|
98
|
-
/**
|
|
99
|
-
* R2 bucket for global object storage.
|
|
100
|
-
*/
|
|
101
|
-
r2;
|
|
102
|
-
/**
|
|
103
|
-
* Filesystem capability for file operations.
|
|
104
|
-
*/
|
|
105
|
-
fs;
|
|
106
|
-
/**
|
|
107
|
-
* Object key prefix in R2.
|
|
108
|
-
*/
|
|
109
|
-
objectPrefix;
|
|
110
|
-
/**
|
|
111
|
-
* Database storage for persistence.
|
|
112
|
-
*/
|
|
113
|
-
storage;
|
|
114
|
-
/**
|
|
115
|
-
* Database row ID for this repository binding.
|
|
116
|
-
*/
|
|
117
|
-
repoId;
|
|
118
|
-
/**
|
|
119
|
-
* Current HEAD commit SHA.
|
|
120
|
-
*/
|
|
121
|
-
currentCommit;
|
|
122
|
-
/**
|
|
123
|
-
* Timestamp of last sync operation.
|
|
124
|
-
*/
|
|
125
|
-
lastSyncTime;
|
|
126
|
-
/**
|
|
127
|
-
* Staged files pending commit.
|
|
128
|
-
*/
|
|
129
|
-
stagedFiles = new Set();
|
|
130
|
-
/**
|
|
131
|
-
* Pending objects to push to R2.
|
|
132
|
-
* Map of SHA to { type, data } for objects that have been committed locally
|
|
133
|
-
* but not yet pushed to the R2 object store.
|
|
134
|
-
*/
|
|
135
|
-
pendingObjects = new Map();
|
|
136
|
-
/**
|
|
137
|
-
* Create a new GitModule instance.
|
|
138
|
-
*
|
|
139
|
-
* @param options - Configuration options
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
|
-
* ```typescript
|
|
143
|
-
* const git = new GitModule({
|
|
144
|
-
* repo: 'org/repo',
|
|
145
|
-
* branch: 'main',
|
|
146
|
-
* r2: env.R2_BUCKET,
|
|
147
|
-
* fs: workflowContext.fs
|
|
148
|
-
* })
|
|
149
|
-
* ```
|
|
150
|
-
*/
|
|
151
|
-
constructor(options) {
|
|
152
|
-
this.repo = options.repo;
|
|
153
|
-
this.branch = options.branch ?? 'main';
|
|
154
|
-
this.path = options.path;
|
|
155
|
-
this.r2 = options.r2;
|
|
156
|
-
this.fs = options.fs;
|
|
157
|
-
this.objectPrefix = options.objectPrefix ?? 'git/objects';
|
|
158
|
-
this.storage = options.storage;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Get the current git binding configuration.
|
|
162
|
-
*
|
|
163
|
-
* @description
|
|
164
|
-
* Returns the binding information connecting this module to a git repository.
|
|
165
|
-
* This includes the repository, branch, path, current commit, and last sync time.
|
|
166
|
-
*
|
|
167
|
-
* @returns Current git binding
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* ```typescript
|
|
171
|
-
* const binding = git.binding
|
|
172
|
-
* console.log(`Repo: ${binding.repo}`)
|
|
173
|
-
* console.log(`Branch: ${binding.branch}`)
|
|
174
|
-
* console.log(`Commit: ${binding.commit ?? 'not synced'}`)
|
|
175
|
-
* ```
|
|
176
|
-
*/
|
|
177
|
-
get binding() {
|
|
178
|
-
return {
|
|
179
|
-
repo: this.repo,
|
|
180
|
-
branch: this.branch,
|
|
181
|
-
path: this.path,
|
|
182
|
-
commit: this.currentCommit,
|
|
183
|
-
lastSync: this.lastSyncTime
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Optional initialization hook.
|
|
188
|
-
* Called when the module is first loaded.
|
|
189
|
-
* When storage is provided, loads or creates the repository binding from the database.
|
|
190
|
-
*/
|
|
191
|
-
async initialize() {
|
|
192
|
-
if (!this.storage)
|
|
193
|
-
return;
|
|
194
|
-
// Try to load existing repository binding
|
|
195
|
-
const existingRows = this.storage.sql.exec('SELECT id, commit, last_sync FROM git WHERE repo = ?', this.repo).toArray();
|
|
196
|
-
if (existingRows.length > 0) {
|
|
197
|
-
// Load existing state
|
|
198
|
-
const row = existingRows[0];
|
|
199
|
-
this.repoId = row.id;
|
|
200
|
-
this.currentCommit = row.commit ?? undefined;
|
|
201
|
-
this.lastSyncTime = row.last_sync ? new Date(row.last_sync) : undefined;
|
|
202
|
-
// Load staged files from git_content table
|
|
203
|
-
const stagedRows = this.storage.sql.exec('SELECT path FROM git_content WHERE repo_id = ? AND status = ?', this.repoId, 'staged').toArray();
|
|
204
|
-
for (const staged of stagedRows) {
|
|
205
|
-
this.stagedFiles.add(staged.path);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
// Create new repository binding
|
|
210
|
-
const now = Date.now();
|
|
211
|
-
this.storage.sql.exec(`INSERT INTO git (repo, path, branch, object_prefix, created_at, updated_at)
|
|
212
|
-
VALUES (?, ?, ?, ?, ?, ?)`, this.repo, this.path ?? null, this.branch, this.objectPrefix, now, now);
|
|
213
|
-
// Get the inserted row ID
|
|
214
|
-
const insertedRows = this.storage.sql.exec('SELECT id FROM git WHERE repo = ?', this.repo).toArray();
|
|
215
|
-
if (insertedRows.length > 0) {
|
|
216
|
-
this.repoId = insertedRows[0].id;
|
|
217
|
-
// Create the branch record
|
|
218
|
-
this.storage.sql.exec(`INSERT INTO git_branches (repo_id, name, tracking, created_at, updated_at)
|
|
219
|
-
VALUES (?, ?, 1, ?, ?)`, this.repoId, this.branch, now, now);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Optional cleanup hook.
|
|
225
|
-
* Called when the capability is unloaded.
|
|
226
|
-
*/
|
|
227
|
-
async dispose() {
|
|
228
|
-
// Cleanup logic if needed
|
|
229
|
-
this.stagedFiles.clear();
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Sync git objects from R2 to local storage via FsModule.
|
|
233
|
-
*
|
|
234
|
-
* @description
|
|
235
|
-
* Fetches git objects from the R2 global object store and writes them
|
|
236
|
-
* to the local filesystem via the FsModule. This syncs the DO's local
|
|
237
|
-
* state with the shared repository state.
|
|
238
|
-
*
|
|
239
|
-
* @returns Result of the sync operation
|
|
240
|
-
*
|
|
241
|
-
* @example
|
|
242
|
-
* ```typescript
|
|
243
|
-
* const result = await git.sync()
|
|
244
|
-
* if (result.success) {
|
|
245
|
-
* console.log(`Synced ${result.objectsFetched} objects`)
|
|
246
|
-
* console.log(`Now at commit ${result.commit}`)
|
|
247
|
-
* } else {
|
|
248
|
-
* console.error(`Sync failed: ${result.error}`)
|
|
249
|
-
* }
|
|
250
|
-
* ```
|
|
251
|
-
*/
|
|
252
|
-
async sync() {
|
|
253
|
-
if (!this.r2) {
|
|
254
|
-
return {
|
|
255
|
-
success: false,
|
|
256
|
-
objectsFetched: 0,
|
|
257
|
-
filesWritten: 0,
|
|
258
|
-
error: 'R2 bucket not configured'
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
if (!this.fs) {
|
|
262
|
-
return {
|
|
263
|
-
success: false,
|
|
264
|
-
objectsFetched: 0,
|
|
265
|
-
filesWritten: 0,
|
|
266
|
-
error: 'Filesystem capability not available'
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
// Get the ref for our branch
|
|
271
|
-
const refKey = `${this.objectPrefix}/refs/heads/${this.branch}`;
|
|
272
|
-
const refObject = await this.r2.get(refKey);
|
|
273
|
-
if (!refObject) {
|
|
274
|
-
// No ref exists yet - this is a new/empty repository
|
|
275
|
-
this.currentCommit = undefined;
|
|
276
|
-
this.lastSyncTime = new Date();
|
|
277
|
-
// Persist sync state to database even for empty repos
|
|
278
|
-
await this.persistSyncState();
|
|
279
|
-
return {
|
|
280
|
-
success: true,
|
|
281
|
-
objectsFetched: 0,
|
|
282
|
-
filesWritten: 0,
|
|
283
|
-
commit: undefined
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
const commitSha = await refObject.text();
|
|
287
|
-
let objectsFetched = 0;
|
|
288
|
-
let filesWritten = 0;
|
|
289
|
-
// Fetch the commit object
|
|
290
|
-
const commitObject = await this.fetchObject(commitSha);
|
|
291
|
-
if (commitObject) {
|
|
292
|
-
objectsFetched++;
|
|
293
|
-
// Parse commit to get tree SHA
|
|
294
|
-
const commitContent = new TextDecoder().decode(commitObject);
|
|
295
|
-
const treeMatch = commitContent.match(/^tree ([a-f0-9]{40})/m);
|
|
296
|
-
if (treeMatch) {
|
|
297
|
-
const treeSha = treeMatch[1];
|
|
298
|
-
// Recursively sync tree contents
|
|
299
|
-
const treeResult = await this.syncTree(treeSha, this.path ?? '');
|
|
300
|
-
objectsFetched += treeResult.objects;
|
|
301
|
-
filesWritten += treeResult.files;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
this.currentCommit = commitSha;
|
|
305
|
-
this.lastSyncTime = new Date();
|
|
306
|
-
// Persist sync state to database
|
|
307
|
-
await this.persistSyncState();
|
|
308
|
-
return {
|
|
309
|
-
success: true,
|
|
310
|
-
objectsFetched,
|
|
311
|
-
filesWritten,
|
|
312
|
-
commit: commitSha
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
catch (error) {
|
|
316
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
317
|
-
return {
|
|
318
|
-
success: false,
|
|
319
|
-
objectsFetched: 0,
|
|
320
|
-
filesWritten: 0,
|
|
321
|
-
error: errorMessage
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Push local changes to R2 object store.
|
|
327
|
-
*
|
|
328
|
-
* @description
|
|
329
|
-
* Writes local git objects to the R2 global object store for
|
|
330
|
-
* cross-DO synchronization. This makes local changes available
|
|
331
|
-
* to other DOs that sync from the same repository.
|
|
332
|
-
*
|
|
333
|
-
* @returns Result of the push operation
|
|
334
|
-
*
|
|
335
|
-
* @example
|
|
336
|
-
* ```typescript
|
|
337
|
-
* // Make changes and commit
|
|
338
|
-
* await git.add('src/index.ts')
|
|
339
|
-
* await git.commit('Update code')
|
|
340
|
-
*
|
|
341
|
-
* // Push to R2
|
|
342
|
-
* const result = await git.push()
|
|
343
|
-
* if (result.success) {
|
|
344
|
-
* console.log(`Pushed ${result.objectsPushed} objects`)
|
|
345
|
-
* }
|
|
346
|
-
* ```
|
|
347
|
-
*/
|
|
348
|
-
async push() {
|
|
349
|
-
if (!this.r2) {
|
|
350
|
-
return {
|
|
351
|
-
success: false,
|
|
352
|
-
objectsPushed: 0,
|
|
353
|
-
error: 'R2 bucket not configured'
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
if (!this.currentCommit) {
|
|
357
|
-
return {
|
|
358
|
-
success: false,
|
|
359
|
-
objectsPushed: 0,
|
|
360
|
-
error: 'No commits to push'
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
try {
|
|
364
|
-
let objectsPushed = 0;
|
|
365
|
-
// Push all pending objects to R2
|
|
366
|
-
for (const [sha, { data }] of this.pendingObjects) {
|
|
367
|
-
await this.storeObject(sha, data);
|
|
368
|
-
objectsPushed++;
|
|
369
|
-
}
|
|
370
|
-
// Clear pending objects after successful push
|
|
371
|
-
this.pendingObjects.clear();
|
|
372
|
-
// Update the ref to point to our current commit
|
|
373
|
-
const refKey = `${this.objectPrefix}/refs/heads/${this.branch}`;
|
|
374
|
-
await this.r2.put(refKey, this.currentCommit);
|
|
375
|
-
return {
|
|
376
|
-
success: true,
|
|
377
|
-
objectsPushed,
|
|
378
|
-
commit: this.currentCommit
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
catch (error) {
|
|
382
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
383
|
-
return {
|
|
384
|
-
success: false,
|
|
385
|
-
objectsPushed: 0,
|
|
386
|
-
error: errorMessage
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* Get the current repository status.
|
|
392
|
-
*
|
|
393
|
-
* @description
|
|
394
|
-
* Returns information about the current branch, HEAD commit,
|
|
395
|
-
* and staged/unstaged files.
|
|
396
|
-
*
|
|
397
|
-
* @returns Status object with branch and file information
|
|
398
|
-
*
|
|
399
|
-
* @example
|
|
400
|
-
* ```typescript
|
|
401
|
-
* const status = await git.status()
|
|
402
|
-
* console.log(`On branch ${status.branch}`)
|
|
403
|
-
* if (status.staged.length > 0) {
|
|
404
|
-
* console.log(`${status.staged.length} files staged`)
|
|
405
|
-
* }
|
|
406
|
-
* ```
|
|
407
|
-
*/
|
|
408
|
-
async status() {
|
|
409
|
-
return {
|
|
410
|
-
branch: this.branch,
|
|
411
|
-
head: this.currentCommit,
|
|
412
|
-
staged: Array.from(this.stagedFiles),
|
|
413
|
-
unstaged: [], // Would need working tree comparison
|
|
414
|
-
clean: this.stagedFiles.size === 0
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Stage files for commit.
|
|
419
|
-
*
|
|
420
|
-
* @description
|
|
421
|
-
* Adds files to the staging area for the next commit.
|
|
422
|
-
*
|
|
423
|
-
* @param files - File path or array of file paths to stage
|
|
424
|
-
*
|
|
425
|
-
* @example
|
|
426
|
-
* ```typescript
|
|
427
|
-
* await git.add('src/index.ts')
|
|
428
|
-
* await git.add(['src/a.ts', 'src/b.ts'])
|
|
429
|
-
* ```
|
|
430
|
-
*/
|
|
431
|
-
async add(files) {
|
|
432
|
-
const filesToAdd = Array.isArray(files) ? files : [files];
|
|
433
|
-
for (const file of filesToAdd) {
|
|
434
|
-
this.stagedFiles.add(file);
|
|
435
|
-
// Persist staged file to database
|
|
436
|
-
await this.persistStagedFile(file);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Create a new commit with staged changes.
|
|
441
|
-
*
|
|
442
|
-
* @description
|
|
443
|
-
* Creates a commit object with the currently staged changes.
|
|
444
|
-
* Returns the commit hash.
|
|
445
|
-
*
|
|
446
|
-
* @param message - Commit message
|
|
447
|
-
* @returns Commit hash or object with hash
|
|
448
|
-
*
|
|
449
|
-
* @example
|
|
450
|
-
* ```typescript
|
|
451
|
-
* await git.add('src/index.ts')
|
|
452
|
-
* const result = await git.commit('Update code')
|
|
453
|
-
* console.log(`Created commit: ${result}`)
|
|
454
|
-
* ```
|
|
455
|
-
*/
|
|
456
|
-
async commit(message) {
|
|
457
|
-
if (this.stagedFiles.size === 0) {
|
|
458
|
-
throw new Error('Nothing to commit - no files staged');
|
|
459
|
-
}
|
|
460
|
-
const encoder = new TextEncoder();
|
|
461
|
-
// Create blob objects for each staged file
|
|
462
|
-
const treeEntries = [];
|
|
463
|
-
for (const filePath of this.stagedFiles) {
|
|
464
|
-
// Read file content from filesystem if available
|
|
465
|
-
let content;
|
|
466
|
-
if (this.fs) {
|
|
467
|
-
try {
|
|
468
|
-
const fileContent = await this.fs.readFile(filePath);
|
|
469
|
-
content = typeof fileContent === 'string'
|
|
470
|
-
? encoder.encode(fileContent)
|
|
471
|
-
: new Uint8Array(fileContent);
|
|
472
|
-
}
|
|
473
|
-
catch {
|
|
474
|
-
// File doesn't exist or can't be read, create empty blob
|
|
475
|
-
content = new Uint8Array(0);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
else {
|
|
479
|
-
// No filesystem, create placeholder content
|
|
480
|
-
content = encoder.encode(`placeholder content for ${filePath}`);
|
|
481
|
-
}
|
|
482
|
-
// Create blob object
|
|
483
|
-
const blobHeader = encoder.encode(`blob ${content.length}\0`);
|
|
484
|
-
const blobData = new Uint8Array(blobHeader.length + content.length);
|
|
485
|
-
blobData.set(blobHeader);
|
|
486
|
-
blobData.set(content, blobHeader.length);
|
|
487
|
-
const blobSha = await this.hashBytes(blobData);
|
|
488
|
-
// Store blob content (without header) for push
|
|
489
|
-
this.pendingObjects.set(blobSha, { type: 'blob', data: content });
|
|
490
|
-
// Add to tree entries (use basename for tree entry name)
|
|
491
|
-
const name = filePath.split('/').pop() || filePath;
|
|
492
|
-
treeEntries.push({ mode: '100644', name, sha: blobSha });
|
|
493
|
-
}
|
|
494
|
-
// Sort tree entries by name (git requirement)
|
|
495
|
-
treeEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
496
|
-
// Create tree object content
|
|
497
|
-
const treeContent = this.buildTreeContent(treeEntries);
|
|
498
|
-
const treeHeader = encoder.encode(`tree ${treeContent.length}\0`);
|
|
499
|
-
const treeData = new Uint8Array(treeHeader.length + treeContent.length);
|
|
500
|
-
treeData.set(treeHeader);
|
|
501
|
-
treeData.set(treeContent, treeHeader.length);
|
|
502
|
-
const treeSha = await this.hashBytes(treeData);
|
|
503
|
-
// Store tree for push
|
|
504
|
-
this.pendingObjects.set(treeSha, { type: 'tree', data: treeContent });
|
|
505
|
-
// Create commit object
|
|
506
|
-
const timestamp = Math.floor(Date.now() / 1000);
|
|
507
|
-
const timezone = '+0000';
|
|
508
|
-
const author = `GitModule <git@gitx.do> ${timestamp} ${timezone}`;
|
|
509
|
-
let commitContent = `tree ${treeSha}\n`;
|
|
510
|
-
if (this.currentCommit) {
|
|
511
|
-
commitContent += `parent ${this.currentCommit}\n`;
|
|
512
|
-
}
|
|
513
|
-
commitContent += `author ${author}\n`;
|
|
514
|
-
commitContent += `committer ${author}\n`;
|
|
515
|
-
commitContent += `\n${message}\n`;
|
|
516
|
-
const commitContentBytes = encoder.encode(commitContent);
|
|
517
|
-
const commitHeader = encoder.encode(`commit ${commitContentBytes.length}\0`);
|
|
518
|
-
const commitData = new Uint8Array(commitHeader.length + commitContentBytes.length);
|
|
519
|
-
commitData.set(commitHeader);
|
|
520
|
-
commitData.set(commitContentBytes, commitHeader.length);
|
|
521
|
-
const commitSha = await this.hashBytes(commitData);
|
|
522
|
-
// Store commit for push
|
|
523
|
-
this.pendingObjects.set(commitSha, { type: 'commit', data: commitContentBytes });
|
|
524
|
-
this.currentCommit = commitSha;
|
|
525
|
-
this.stagedFiles.clear();
|
|
526
|
-
// Persist commit state to database and clear staged files
|
|
527
|
-
await this.persistCommitState(commitSha);
|
|
528
|
-
return { hash: commitSha };
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Build tree content from entries.
|
|
532
|
-
* Format: mode name\0sha20bytes (repeated)
|
|
533
|
-
*/
|
|
534
|
-
buildTreeContent(entries) {
|
|
535
|
-
const encoder = new TextEncoder();
|
|
536
|
-
const parts = [];
|
|
537
|
-
for (const entry of entries) {
|
|
538
|
-
const modeAndName = encoder.encode(`${entry.mode} ${entry.name}\0`);
|
|
539
|
-
const sha20 = this.hexToBytes(entry.sha);
|
|
540
|
-
const entryData = new Uint8Array(modeAndName.length + 20);
|
|
541
|
-
entryData.set(modeAndName);
|
|
542
|
-
entryData.set(sha20, modeAndName.length);
|
|
543
|
-
parts.push(entryData);
|
|
544
|
-
}
|
|
545
|
-
// Combine all parts
|
|
546
|
-
const totalLength = parts.reduce((sum, part) => sum + part.length, 0);
|
|
547
|
-
const result = new Uint8Array(totalLength);
|
|
548
|
-
let offset = 0;
|
|
549
|
-
for (const part of parts) {
|
|
550
|
-
result.set(part, offset);
|
|
551
|
-
offset += part.length;
|
|
552
|
-
}
|
|
553
|
-
return result;
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Convert hex string to bytes.
|
|
557
|
-
*/
|
|
558
|
-
hexToBytes(hex) {
|
|
559
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
560
|
-
for (let i = 0; i < hex.length; i += 2) {
|
|
561
|
-
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
|
562
|
-
}
|
|
563
|
-
return bytes;
|
|
564
|
-
}
|
|
565
|
-
/**
|
|
566
|
-
* Hash raw bytes using SHA-1.
|
|
567
|
-
*/
|
|
568
|
-
async hashBytes(data) {
|
|
569
|
-
// Create a copy as ArrayBuffer to satisfy BufferSource type
|
|
570
|
-
const buffer = new ArrayBuffer(data.length);
|
|
571
|
-
new Uint8Array(buffer).set(data);
|
|
572
|
-
const hashBuffer = await crypto.subtle.digest('SHA-1', buffer);
|
|
573
|
-
return this.bytesToHex(new Uint8Array(hashBuffer));
|
|
574
|
-
}
|
|
575
|
-
/**
|
|
576
|
-
* Get diff between references or working tree.
|
|
577
|
-
*
|
|
578
|
-
* @param _ref - Reference to diff against (not yet implemented)
|
|
579
|
-
* @returns Unified diff output
|
|
580
|
-
*/
|
|
581
|
-
async diff(_ref) {
|
|
582
|
-
// Placeholder - would need full diff implementation
|
|
583
|
-
return `diff --git a/ b/\n(diff not yet implemented)`;
|
|
584
|
-
}
|
|
585
|
-
/**
|
|
586
|
-
* Get commit history.
|
|
587
|
-
*
|
|
588
|
-
* @param _options - Options for filtering results (not yet implemented)
|
|
589
|
-
* @returns Array of commit objects
|
|
590
|
-
*/
|
|
591
|
-
async log(_options) {
|
|
592
|
-
// Placeholder - would need commit traversal
|
|
593
|
-
if (this.currentCommit) {
|
|
594
|
-
return [{ hash: this.currentCommit, message: 'Current commit' }];
|
|
595
|
-
}
|
|
596
|
-
return [];
|
|
597
|
-
}
|
|
598
|
-
/**
|
|
599
|
-
* Pull changes from R2 (alias for sync).
|
|
600
|
-
*
|
|
601
|
-
* @param _remote - Remote name (ignored, always uses R2)
|
|
602
|
-
* @param _branch - Branch to pull (uses configured branch)
|
|
603
|
-
*/
|
|
604
|
-
async pull(_remote, _branch) {
|
|
605
|
-
const result = await this.sync();
|
|
606
|
-
if (!result.success) {
|
|
607
|
-
throw new Error(result.error ?? 'Pull failed');
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
611
|
-
// Private Helper Methods
|
|
612
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
613
|
-
/**
|
|
614
|
-
* Fetch a git object from R2 by SHA.
|
|
615
|
-
*/
|
|
616
|
-
async fetchObject(sha) {
|
|
617
|
-
if (!this.r2)
|
|
618
|
-
return null;
|
|
619
|
-
const key = `${this.objectPrefix}/${sha.slice(0, 2)}/${sha.slice(2)}`;
|
|
620
|
-
const object = await this.r2.get(key);
|
|
621
|
-
if (!object)
|
|
622
|
-
return null;
|
|
623
|
-
const buffer = await object.arrayBuffer();
|
|
624
|
-
return new Uint8Array(buffer);
|
|
625
|
-
}
|
|
626
|
-
/**
|
|
627
|
-
* Store a git object in R2.
|
|
628
|
-
*/
|
|
629
|
-
async storeObject(sha, data) {
|
|
630
|
-
if (!this.r2)
|
|
631
|
-
return;
|
|
632
|
-
const key = `${this.objectPrefix}/${sha.slice(0, 2)}/${sha.slice(2)}`;
|
|
633
|
-
await this.r2.put(key, data);
|
|
634
|
-
}
|
|
635
|
-
/**
|
|
636
|
-
* Recursively sync a tree and its contents.
|
|
637
|
-
*/
|
|
638
|
-
async syncTree(treeSha, basePath) {
|
|
639
|
-
let objects = 0;
|
|
640
|
-
let files = 0;
|
|
641
|
-
const treeData = await this.fetchObject(treeSha);
|
|
642
|
-
if (!treeData)
|
|
643
|
-
return { objects, files };
|
|
644
|
-
objects++;
|
|
645
|
-
// Parse tree entries
|
|
646
|
-
// Tree format: mode name\0sha20bytes (repeated)
|
|
647
|
-
let offset = 0;
|
|
648
|
-
const decoder = new TextDecoder();
|
|
649
|
-
while (offset < treeData.length) {
|
|
650
|
-
// Find the null byte
|
|
651
|
-
let nullIdx = offset;
|
|
652
|
-
while (nullIdx < treeData.length && treeData[nullIdx] !== 0) {
|
|
653
|
-
nullIdx++;
|
|
654
|
-
}
|
|
655
|
-
const modeAndName = decoder.decode(treeData.slice(offset, nullIdx));
|
|
656
|
-
const spaceIdx = modeAndName.indexOf(' ');
|
|
657
|
-
const mode = modeAndName.slice(0, spaceIdx);
|
|
658
|
-
const name = modeAndName.slice(spaceIdx + 1);
|
|
659
|
-
// Read 20-byte SHA
|
|
660
|
-
const sha20 = treeData.slice(nullIdx + 1, nullIdx + 21);
|
|
661
|
-
const sha = this.bytesToHex(sha20);
|
|
662
|
-
const entryPath = basePath ? `${basePath}/${name}` : name;
|
|
663
|
-
if (mode === '40000' || mode === '040000') {
|
|
664
|
-
// Directory - recurse
|
|
665
|
-
const subResult = await this.syncTree(sha, entryPath);
|
|
666
|
-
objects += subResult.objects;
|
|
667
|
-
files += subResult.files;
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
// File - fetch blob and write via fs
|
|
671
|
-
const blobData = await this.fetchObject(sha);
|
|
672
|
-
if (blobData && this.fs) {
|
|
673
|
-
objects++;
|
|
674
|
-
// Ensure parent directory exists
|
|
675
|
-
const parentDir = entryPath.split('/').slice(0, -1).join('/');
|
|
676
|
-
if (parentDir) {
|
|
677
|
-
await this.fs.mkdir(`/${parentDir}`, { recursive: true });
|
|
678
|
-
}
|
|
679
|
-
// Write file content (skip git header if present)
|
|
680
|
-
await this.fs.writeFile(`/${entryPath}`, Buffer.from(blobData));
|
|
681
|
-
files++;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
offset = nullIdx + 21;
|
|
685
|
-
}
|
|
686
|
-
return { objects, files };
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* Convert bytes to hex string.
|
|
690
|
-
*/
|
|
691
|
-
bytesToHex(bytes) {
|
|
692
|
-
return Array.from(bytes)
|
|
693
|
-
.map(b => b.toString(16).padStart(2, '0'))
|
|
694
|
-
.join('');
|
|
695
|
-
}
|
|
696
|
-
/**
|
|
697
|
-
* Persist sync state to the database.
|
|
698
|
-
* Updates the git table with the current commit and last sync timestamp.
|
|
699
|
-
*/
|
|
700
|
-
async persistSyncState() {
|
|
701
|
-
if (!this.storage || !this.repoId)
|
|
702
|
-
return;
|
|
703
|
-
const now = Date.now();
|
|
704
|
-
this.storage.sql.exec(`UPDATE git SET commit = ?, last_sync = ?, updated_at = ? WHERE id = ?`, this.currentCommit ?? null, now, now, this.repoId);
|
|
705
|
-
}
|
|
706
|
-
/**
|
|
707
|
-
* Persist a staged file to the database.
|
|
708
|
-
* Inserts or updates a record in the git_content table.
|
|
709
|
-
* Uses file_id foreign key to reference the shared files table when available.
|
|
710
|
-
*/
|
|
711
|
-
async persistStagedFile(file) {
|
|
712
|
-
if (!this.storage || !this.repoId)
|
|
713
|
-
return;
|
|
714
|
-
const now = Date.now();
|
|
715
|
-
// Get file_id from filesystem if getFileId is available
|
|
716
|
-
let fileId = null;
|
|
717
|
-
if (this.fs?.getFileId) {
|
|
718
|
-
try {
|
|
719
|
-
fileId = await this.fs.getFileId(file);
|
|
720
|
-
}
|
|
721
|
-
catch {
|
|
722
|
-
// File may not exist in filesystem yet, that's okay
|
|
723
|
-
fileId = null;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
// Use INSERT OR REPLACE to handle both new and existing files
|
|
727
|
-
// Include file_id for efficient foreign key relationships
|
|
728
|
-
this.storage.sql.exec(`INSERT INTO git_content (repo_id, file_id, path, status, created_at, updated_at)
|
|
729
|
-
VALUES (?, ?, ?, 'staged', ?, ?)
|
|
730
|
-
ON CONFLICT(repo_id, path) DO UPDATE SET status = 'staged', file_id = ?, updated_at = ?`, this.repoId, fileId, file, now, now, fileId, now);
|
|
731
|
-
}
|
|
732
|
-
/**
|
|
733
|
-
* Persist commit state to the database.
|
|
734
|
-
* Updates the git table with the new commit hash and clears staged files.
|
|
735
|
-
*/
|
|
736
|
-
async persistCommitState(hash) {
|
|
737
|
-
if (!this.storage || !this.repoId)
|
|
738
|
-
return;
|
|
739
|
-
const now = Date.now();
|
|
740
|
-
// Update the commit hash in the git table
|
|
741
|
-
this.storage.sql.exec(`UPDATE git SET commit = ?, updated_at = ? WHERE id = ?`, hash, now, this.repoId);
|
|
742
|
-
// Update branch head
|
|
743
|
-
this.storage.sql.exec(`UPDATE git_branches SET head = ?, updated_at = ? WHERE repo_id = ? AND name = ?`, hash, now, this.repoId, this.branch);
|
|
744
|
-
// Clear staged files from git_content
|
|
745
|
-
this.storage.sql.exec(`DELETE FROM git_content WHERE repo_id = ? AND status = 'staged'`, this.repoId);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
// ============================================================================
|
|
749
|
-
// Factory Functions
|
|
750
|
-
// ============================================================================
|
|
751
|
-
/**
|
|
752
|
-
* Create a GitModule instance with the given options.
|
|
753
|
-
*
|
|
754
|
-
* @param options - Configuration options for the module
|
|
755
|
-
* @returns A new GitModule instance
|
|
756
|
-
*
|
|
757
|
-
* @example
|
|
758
|
-
* ```typescript
|
|
759
|
-
* import { createGitModule } from 'gitx.do/do'
|
|
760
|
-
*
|
|
761
|
-
* const git = createGitModule({
|
|
762
|
-
* repo: 'org/repo',
|
|
763
|
-
* branch: 'main',
|
|
764
|
-
* r2: env.R2_BUCKET,
|
|
765
|
-
* fs: workflowContext.fs
|
|
766
|
-
* })
|
|
767
|
-
* ```
|
|
768
|
-
*/
|
|
769
|
-
export function createGitModule(options) {
|
|
770
|
-
return new GitModule(options);
|
|
771
|
-
}
|
|
772
|
-
// ============================================================================
|
|
773
|
-
// Type Guards
|
|
774
|
-
// ============================================================================
|
|
775
|
-
/**
|
|
776
|
-
* Check if a value is a GitModule instance.
|
|
777
|
-
*
|
|
778
|
-
* @param value - Value to check
|
|
779
|
-
* @returns True if value is a GitModule
|
|
780
|
-
*/
|
|
781
|
-
export function isGitModule(value) {
|
|
782
|
-
return value instanceof GitModule;
|
|
783
|
-
}
|
|
784
|
-
//# sourceMappingURL=GitModule.js.map
|