+3
-3
Dockerfile
+3
-3
Dockerfile
···
18
18
RUN CGO_ENABLED=1 go build \
19
19
-ldflags="-w -s -X 'main.version=${VERSION}' -X 'main.gitCommit=${GIT_COMMIT}' -X 'main.buildDate=${BUILD_DATE}'" \
20
20
-trimpath \
21
-
-o plcbundle \
21
+
-o plcbundle-go \
22
22
./cmd/plcbundle
23
23
24
24
FROM alpine:3.19
25
25
26
26
RUN apk add --no-cache ca-certificates zstd-libs
27
27
28
-
COPY --from=builder /build/plcbundle /usr/local/bin/plcbundle
28
+
COPY --from=builder /build/plcbundle-go /usr/local/bin/plcbundle-go
29
29
30
30
WORKDIR /data
31
31
32
-
ENTRYPOINT ["plcbundle"]
32
+
ENTRYPOINT ["plcbundle-go"]
+8
-8
Makefile
+8
-8
Makefile
···
2
2
.PHONY: docker-build docker-buildx docker-push docker-run docker-clean docker-shell compose-up compose-down compose-logs
3
3
4
4
# Binary name
5
-
BINARY_NAME=plcbundle
5
+
BINARY_NAME=plcbundle-go
6
6
INSTALL_PATH=$(GOPATH)/bin
7
7
8
8
# Docker configuration
9
-
DOCKER_IMAGE=plcbundle
9
+
DOCKER_IMAGE=plcbundle-go
10
10
DOCKER_TAG=$(VERSION)
11
11
DOCKER_REGISTRY?=atscan
12
12
DOCKER_FULL_IMAGE=$(if $(DOCKER_REGISTRY),$(DOCKER_REGISTRY)/,)$(DOCKER_IMAGE):$(DOCKER_TAG)
···
45
45
# Install the CLI tool globally
46
46
install:
47
47
@echo "Installing $(BINARY_NAME) ..."
48
-
$(GOINSTALL) $(LDFLAGS) ./cmd/plcbundle
48
+
$(GOBUILD) $(LDFLAGS) -o $(INSTALL_PATH)/$(BINARY_NAME) ./cmd/plcbundle
49
49
50
50
# Run tests
51
51
test:
···
157
157
158
158
# Run Docker container as CLI
159
159
docker-run:
160
-
@docker run --rm -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle $(CMD)
160
+
@docker run --rm -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle-go $(CMD)
161
161
162
162
# Shortcuts
163
163
docker-info:
164
-
@docker run --rm -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle info
164
+
@docker run --rm -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle-go info
165
165
166
166
docker-fetch:
167
-
@docker run --rm -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle fetch
167
+
@docker run --rm -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle-go fetch
168
168
169
169
docker-verify:
170
-
@docker run --rm -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle verify
170
+
@docker run --rm -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle-go verify
171
171
172
172
# Run as server
173
173
docker-serve:
174
-
docker run --rm -it -p 8080:8080 -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle serve --host 0.0.0.0
174
+
docker run --rm -it -p 8080:8080 -v $(PWD)/data:/data $(DOCKER_FULL_IMAGE) plcbundle-go serve --host 0.0.0.0
175
175
176
176
# Open shell
177
177
docker-shell:
+9
-9
README.md
+9
-9
README.md
···
70
70
71
71
```bash
72
72
# CLI tool
73
-
go install tangled.org/atscan.net/plcbundle/cmd/plcbundle@latest
73
+
go install tangled.org/atscan.net/plcbundle-go/cmd/plcbundle@latest
74
74
75
75
# Library
76
-
go get tangled.org/atscan.net/plcbundle
76
+
go get tangled.org/atscan.net/plcbundle-go
77
77
```
78
78
79
79
### Docker
···
87
87
docker pull atscan/plcbundle:latest
88
88
89
89
# Run CLI
90
-
docker run --rm -v $(pwd)/data:/data atscan/plcbundle info
90
+
docker run --rm -v $(pwd)/data:/data atscan/plcbundle-go info
91
91
92
92
# Run as server
93
-
docker run -d -p 8080:8080 -v $(pwd)/data:/data atscan/plcbundle serve --host 0.0.0.0
93
+
docker run -d -p 8080:8080 -v $(pwd)/data:/data atscan/plcbundle-go serve --host 0.0.0.0
94
94
95
95
# Or use docker compose
96
96
curl -O https://tangled.org/@atscan.net/plcbundle/raw/main/docker-compose.yaml
···
111
111
### As a Library
112
112
113
113
```go
114
-
import plcbundle "tangled.org/atscan.net/plcbundle"
114
+
import plcbundle "tangled.org/atscan.net/plcbundle-go"
115
115
116
116
mgr, _ := plcbundle.New("./plc_data", "https://plc.directory")
117
117
defer mgr.Close()
···
126
126
127
127
```bash
128
128
# Fetch bundles from plc.directory
129
-
plcbundle sync
129
+
plcbundle-go sync
130
130
131
131
# Clone from remote
132
-
plcbundle clone https://plc.example.com
132
+
plcbundle-go clone https://plc.example.com
133
133
134
134
# Verify integrity
135
-
plcbundle verify
135
+
plcbundle-go verify
136
136
```
137
137
138
138
[See full CLI reference โ](./docs/cli.md)
···
141
141
142
142
```bash
143
143
# CLI usage
144
-
docker run --rm -v $(pwd)/data:/data plcbundle info
144
+
docker run --rm -v $(pwd)/data:/data plcbundle-go info
145
145
146
146
# Server mode
147
147
docker-compose up -d
+6
-6
bundle/bundle_test.go
+6
-6
bundle/bundle_test.go
···
5
5
"testing"
6
6
"time"
7
7
8
-
"tangled.org/atscan.net/plcbundle/bundle"
9
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
10
-
"tangled.org/atscan.net/plcbundle/internal/mempool"
11
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
12
-
"tangled.org/atscan.net/plcbundle/internal/storage"
13
-
"tangled.org/atscan.net/plcbundle/internal/types"
8
+
"tangled.org/atscan.net/plcbundle-go/bundle"
9
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
10
+
"tangled.org/atscan.net/plcbundle-go/internal/mempool"
11
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
12
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
13
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
14
14
)
15
15
16
16
var (
+56
-33
bundle/manager.go
+56
-33
bundle/manager.go
···
15
15
"sync/atomic"
16
16
"time"
17
17
18
-
plcbundle "tangled.org/atscan.net/plcbundle-rs/bindings/go"
19
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
20
-
"tangled.org/atscan.net/plcbundle/internal/didindex"
21
-
"tangled.org/atscan.net/plcbundle/internal/handleresolver"
22
-
"tangled.org/atscan.net/plcbundle/internal/mempool"
23
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
24
-
"tangled.org/atscan.net/plcbundle/internal/storage"
25
-
internalsync "tangled.org/atscan.net/plcbundle/internal/sync"
26
-
"tangled.org/atscan.net/plcbundle/internal/types"
18
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
19
+
"tangled.org/atscan.net/plcbundle-go/internal/didindex"
20
+
"tangled.org/atscan.net/plcbundle-go/internal/handleresolver"
21
+
"tangled.org/atscan.net/plcbundle-go/internal/mempool"
22
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
23
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
24
+
internalsync "tangled.org/atscan.net/plcbundle-go/internal/sync"
25
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
27
26
)
28
27
29
28
// defaultLogger is a simple logger implementation
···
76
75
recentIdx int
77
76
recentSize int
78
77
}
79
-
80
-
// Rust-based bundle manager for high-performance operations
81
-
rsManager *plcbundle.BundleManager
82
-
rsManagerOnce sync.Once
83
-
rsManagerErr error
84
78
}
85
79
86
80
// NewManager creates a new bundle manager
···
353
347
return m, nil
354
348
}
355
349
356
-
// getRSManager lazily initializes the Rust bundle manager
357
-
func (m *Manager) getRSManager() (*plcbundle.BundleManager, error) {
358
-
m.rsManagerOnce.Do(func() {
359
-
rsMgr, err := plcbundle.NewBundleManager(m.config.BundleDir)
360
-
if err != nil {
361
-
m.rsManagerErr = fmt.Errorf("failed to create Rust bundle manager: %w", err)
362
-
return
363
-
}
364
-
m.rsManager = rsMgr
365
-
})
366
-
return m.rsManager, m.rsManagerErr
367
-
}
368
-
369
350
// Close cleans up resources
370
351
func (m *Manager) Close() {
371
-
if m.rsManager != nil {
372
-
m.rsManager.Close()
373
-
}
374
352
if m.operations != nil {
375
353
m.operations.Close()
376
354
}
···
731
709
return stats
732
710
}
733
711
734
-
// GetRSManager returns the Rust bundle manager (proxy method)
735
-
func (m *Manager) GetRSManager() (*plcbundle.BundleManager, error) {
736
-
return m.getRSManager()
712
+
// ExportOperations exports operations from bundles
713
+
func (m *Manager) ExportOperations(ctx context.Context, afterTime time.Time, count int) ([]plcclient.PLCOperation, error) {
714
+
if count <= 0 {
715
+
count = 1000
716
+
}
717
+
718
+
var result []plcclient.PLCOperation
719
+
seenCIDs := make(map[string]bool)
720
+
721
+
bundles := m.index.GetBundles()
722
+
723
+
for _, meta := range bundles {
724
+
if result != nil && len(result) >= count {
725
+
break
726
+
}
727
+
728
+
// Skip bundles before afterTime
729
+
if !afterTime.IsZero() && meta.EndTime.Before(afterTime) {
730
+
continue
731
+
}
732
+
733
+
// Load bundle
734
+
bundle, err := m.LoadBundle(ctx, meta.BundleNumber)
735
+
if err != nil {
736
+
m.logger.Printf("Warning: failed to load bundle %d: %v", meta.BundleNumber, err)
737
+
continue
738
+
}
739
+
740
+
// Add operations
741
+
for _, op := range bundle.Operations {
742
+
if !afterTime.IsZero() && op.CreatedAt.Before(afterTime) {
743
+
continue
744
+
}
745
+
746
+
if seenCIDs[op.CID] {
747
+
continue
748
+
}
749
+
750
+
seenCIDs[op.CID] = true
751
+
result = append(result, op)
752
+
753
+
if len(result) >= count {
754
+
break
755
+
}
756
+
}
757
+
}
758
+
759
+
return result, nil
737
760
}
738
761
739
762
// IsBundleIndexed checks if a bundle is already in the index
+3
-3
bundle/metadata.go
+3
-3
bundle/metadata.go
···
7
7
"os"
8
8
"time"
9
9
10
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
11
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
12
-
"tangled.org/atscan.net/plcbundle/internal/storage"
10
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
11
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
12
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
13
13
)
14
14
15
15
// CalculateBundleMetadata calculates complete metadata for a bundle
+1
-1
bundle/scanner.go
+1
-1
bundle/scanner.go
+3
-3
bundle/types.go
+3
-3
bundle/types.go
···
5
5
"path/filepath"
6
6
"time"
7
7
8
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
9
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
10
-
"tangled.org/atscan.net/plcbundle/internal/types"
8
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
9
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
10
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
11
11
)
12
12
13
13
// Bundle represents a PLC bundle
+1
-1
bundle.go
+1
-1
bundle.go
+7
-7
cmd/plcbundle/commands/clone.go
+7
-7
cmd/plcbundle/commands/clone.go
···
12
12
"time"
13
13
14
14
"github.com/spf13/cobra"
15
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/ui"
16
-
internalsync "tangled.org/atscan.net/plcbundle/internal/sync"
15
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/ui"
16
+
internalsync "tangled.org/atscan.net/plcbundle-go/internal/sync"
17
17
)
18
18
19
19
func NewCloneCommand() *cobra.Command {
···
43
43
Args: cobra.RangeArgs(1, 2),
44
44
45
45
Example: ` # Clone into default 'bundles' directory
46
-
plcbundle clone https://plc.example.com
46
+
plcbundle-go clone https://plc.example.com
47
47
48
48
# Clone into specific directory
49
-
plcbundle clone https://plc.example.com my-plc-data
49
+
plcbundle-go clone https://plc.example.com my-plc-data
50
50
51
51
# Clone with more parallel workers (faster)
52
-
plcbundle clone https://plc.example.com --workers 8
52
+
plcbundle-go clone https://plc.example.com --workers 8
53
53
54
54
# Resume interrupted clone
55
-
plcbundle clone https://plc.example.com --resume
55
+
plcbundle-go clone https://plc.example.com --resume
56
56
57
57
# Verbose output (shows each bundle)
58
-
plcbundle clone https://plc.example.com my-bundles -v`,
58
+
plcbundle-go clone https://plc.example.com my-bundles -v`,
59
59
60
60
RunE: func(cmd *cobra.Command, args []string) error {
61
61
remoteURL := strings.TrimSuffix(args[0], "/")
+6
-13
cmd/plcbundle/commands/common.go
+6
-13
cmd/plcbundle/commands/common.go
···
9
9
"time"
10
10
11
11
"github.com/spf13/cobra"
12
-
"tangled.org/atscan.net/plcbundle/bundle"
13
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
14
-
"tangled.org/atscan.net/plcbundle/internal/didindex"
15
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
16
-
internalsync "tangled.org/atscan.net/plcbundle/internal/sync"
17
-
"tangled.org/atscan.net/plcbundle/internal/types"
12
+
"tangled.org/atscan.net/plcbundle-go/bundle"
13
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
14
+
"tangled.org/atscan.net/plcbundle-go/internal/didindex"
15
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
16
+
internalsync "tangled.org/atscan.net/plcbundle-go/internal/sync"
17
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
18
18
)
19
19
20
20
// BundleManager interface (for testing/mocking)
···
291
291
}
292
292
return b
293
293
}
294
-
295
-
// getVerboseQuiet extracts verbose and quiet flags from command
296
-
func getVerboseQuiet(cmd *cobra.Command) (verbose, quiet bool) {
297
-
verbose, _ = cmd.Root().PersistentFlags().GetBool("verbose")
298
-
quiet, _ = cmd.Root().PersistentFlags().GetBool("quiet")
299
-
return verbose, quiet
300
-
}
+33
-33
cmd/plcbundle/commands/detector.go
+33
-33
cmd/plcbundle/commands/detector.go
···
15
15
16
16
"github.com/goccy/go-json"
17
17
"github.com/spf13/cobra"
18
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/ui"
19
-
"tangled.org/atscan.net/plcbundle/detector"
20
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
18
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/ui"
19
+
"tangled.org/atscan.net/plcbundle-go/detector"
20
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
21
21
)
22
22
23
23
func NewDetectorCommand() *cobra.Command {
···
41
41
Load JavaScript detectors from .js files with a detect() function.`,
42
42
43
43
Example: ` # List available detectors
44
-
plcbundle detector list
44
+
plcbundle-go detector list
45
45
46
46
# Run detector on bundles
47
-
plcbundle detector run invalid_handle --bundles 1-100
47
+
plcbundle-go detector run invalid_handle --bundles 1-100
48
48
49
49
# Run with parallel processing
50
-
plcbundle detector run invalid_handle --bundles 1-100 --workers 8
50
+
plcbundle-go detector run invalid_handle --bundles 1-100 --workers 8
51
51
52
52
# Run custom detector script
53
-
plcbundle detector run ./my_detector.js --bundles 1-100
53
+
plcbundle-go detector run ./my_detector.js --bundles 1-100
54
54
55
55
# Run multiple detectors
56
-
plcbundle detector run invalid_handle aka_spam --bundles 1-100
56
+
plcbundle-go detector run invalid_handle aka_spam --bundles 1-100
57
57
58
58
# Run all detectors
59
-
plcbundle detector run all --bundles 1-100
59
+
plcbundle-go detector run all --bundles 1-100
60
60
61
61
# Filter JSONL from stdin
62
-
cat ops.jsonl | plcbundle detector filter invalid_handle > clean.jsonl
62
+
cat ops.jsonl | plcbundle-go detector filter invalid_handle > clean.jsonl
63
63
64
64
# Get detector info
65
-
plcbundle detector info invalid_handle`,
65
+
plcbundle-go detector info invalid_handle`,
66
66
}
67
67
68
68
// Add subcommands
···
86
86
Long: `List all available built-in and loaded detectors`,
87
87
88
88
Example: ` # List all detectors
89
-
plcbundle detector list`,
89
+
plcbundle-go detector list`,
90
90
91
91
RunE: func(cmd *cobra.Command, args []string) error {
92
92
registry := detector.DefaultRegistry()
···
100
100
for _, d := range detectors {
101
101
fmt.Printf(" %-20s %s (v%s)\n", d.Name(), d.Description(), d.Version())
102
102
}
103
-
fmt.Printf("\nUse 'plcbundle detector info <name>' for details\n")
103
+
fmt.Printf("\nUse 'plcbundle-go detector info <name>' for details\n")
104
104
105
105
return nil
106
106
},
···
124
124
Long: `Test a detector on a specific bundle and show results`,
125
125
126
126
Example: ` # Test on bundle 42
127
-
plcbundle detector test invalid_handle --bundle 42
127
+
plcbundle-go detector test invalid_handle --bundle 42
128
128
129
129
# Verbose output with samples
130
-
plcbundle detector test aka_spam --bundle 100 -v
130
+
plcbundle-go detector test aka_spam --bundle 100 -v
131
131
132
132
# Custom confidence threshold
133
-
plcbundle detector test spam_pds --bundle 50 --confidence 0.85`,
133
+
plcbundle-go detector test spam_pds --bundle 50 --confidence 0.85`,
134
134
135
135
Args: cobra.ExactArgs(1),
136
136
···
234
234
โข Special keyword 'all' to run all built-in detectors`,
235
235
236
236
Example: ` # Run single detector
237
-
plcbundle detector run invalid_handle --bundles 1-100
237
+
plcbundle-go detector run invalid_handle --bundles 1-100
238
238
239
239
# Run with 8 parallel workers (faster)
240
-
plcbundle detector run invalid_handle --bundles 1-1000 --workers 8
240
+
plcbundle-go detector run invalid_handle --bundles 1-1000 --workers 8
241
241
242
242
# Run multiple detectors in parallel
243
-
plcbundle detector run invalid_handle aka_spam --bundles 1-100 -w 4
243
+
plcbundle-go detector run invalid_handle aka_spam --bundles 1-100 -w 4
244
244
245
245
# Run custom script
246
-
plcbundle detector run ./my_detector.js --bundles 1-100
246
+
plcbundle-go detector run ./my_detector.js --bundles 1-100
247
247
248
248
# Run all built-in detectors
249
-
plcbundle detector run all --bundles 1-100 --workers 8
249
+
plcbundle-go detector run all --bundles 1-100 --workers 8
250
250
251
251
# Save results to file
252
-
plcbundle detector run all --bundles 1-100 -w 8 > results.csv
252
+
plcbundle-go detector run all --bundles 1-100 -w 8 > results.csv
253
253
254
254
# Disable progress bar (for scripting)
255
-
plcbundle detector run spam --bundles 1-100 --no-progress
255
+
plcbundle-go detector run spam --bundles 1-100 --no-progress
256
256
257
257
# Enable profiling
258
-
plcbundle detector run all --bundles 1-100 --pprof :6060`,
258
+
plcbundle-go detector run all --bundles 1-100 --pprof :6060`,
259
259
260
260
Args: cobra.MinimumNArgs(1),
261
261
···
344
344
Perfect for cleaning datasets or pre-processing.`,
345
345
346
346
Example: ` # Filter with built-in detector
347
-
cat ops.jsonl | plcbundle detector filter invalid_handle > clean.jsonl
347
+
cat ops.jsonl | plcbundle-go detector filter invalid_handle > clean.jsonl
348
348
349
349
# Filter with custom script
350
-
plcbundle export --all | plcbundle detector filter ./spam.js > clean.jsonl
350
+
plcbundle export --all | plcbundle-go detector filter ./spam.js > clean.jsonl
351
351
352
352
# Chain multiple detectors
353
-
cat ops.jsonl | plcbundle detector filter invalid_handle aka_spam > clean.jsonl
353
+
cat ops.jsonl | plcbundle-go detector filter invalid_handle aka_spam > clean.jsonl
354
354
355
355
# Custom confidence
356
-
cat ops.jsonl | plcbundle detector filter spam_pds --confidence 0.95 > clean.jsonl`,
356
+
cat ops.jsonl | plcbundle-go detector filter spam_pds --confidence 0.95 > clean.jsonl`,
357
357
358
358
Args: cobra.MinimumNArgs(1),
359
359
···
388
388
Long: `Show detailed information about a specific detector`,
389
389
390
390
Example: ` # Show detector info
391
-
plcbundle detector info invalid_handle
392
-
plcbundle detector info aka_spam`,
391
+
plcbundle-go detector info invalid_handle
392
+
plcbundle-go detector info aka_spam`,
393
393
394
394
Args: cobra.ExactArgs(1),
395
395
···
408
408
409
409
fmt.Printf("Usage examples:\n")
410
410
fmt.Printf(" # Test on single bundle\n")
411
-
fmt.Printf(" plcbundle detector test %s --bundle 42\n\n", d.Name())
411
+
fmt.Printf(" plcbundle-go detector test %s --bundle 42\n\n", d.Name())
412
412
fmt.Printf(" # Run on range and save\n")
413
-
fmt.Printf(" plcbundle detector run %s --bundles 1-100 > results.csv\n\n", d.Name())
413
+
fmt.Printf(" plcbundle-go detector run %s --bundles 1-100 > results.csv\n\n", d.Name())
414
414
fmt.Printf(" # Filter JSONL stream\n")
415
-
fmt.Printf(" cat ops.jsonl | plcbundle detector filter %s > clean.jsonl\n\n", d.Name())
415
+
fmt.Printf(" cat ops.jsonl | plcbundle-go detector filter %s > clean.jsonl\n\n", d.Name())
416
416
417
417
return nil
418
418
},
+36
-36
cmd/plcbundle/commands/did.go
+36
-36
cmd/plcbundle/commands/did.go
···
11
11
12
12
"github.com/goccy/go-json"
13
13
"github.com/spf13/cobra"
14
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/ui"
15
-
"tangled.org/atscan.net/plcbundle/internal/didindex"
16
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
14
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/ui"
15
+
"tangled.org/atscan.net/plcbundle-go/internal/didindex"
16
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
17
17
)
18
18
19
19
func NewDIDCommand() *cobra.Command {
···
27
27
require a DID index to be built for optimal performance.`,
28
28
29
29
Example: ` # Lookup all operations for a DID
30
-
plcbundle did lookup did:plc:524tuhdhh3m7li5gycdn6boe
30
+
plcbundle-go did lookup did:plc:524tuhdhh3m7li5gycdn6boe
31
31
32
32
# Resolve to current DID document
33
-
plcbundle did resolve did:plc:524tuhdhh3m7li5gycdn6boe
33
+
plcbundle-go did resolve did:plc:524tuhdhh3m7li5gycdn6boe
34
34
35
35
# Show complete audit log
36
-
plcbundle did history did:plc:524tuhdhh3m7li5gycdn6boe
36
+
plcbundle-go did history did:plc:524tuhdhh3m7li5gycdn6boe
37
37
38
38
# Show DID statistics
39
-
plcbundle did stats did:plc:524tuhdhh3m7li5gycdn6boe
39
+
plcbundle-go did stats did:plc:524tuhdhh3m7li5gycdn6boe
40
40
41
41
# Batch process from file
42
-
plcbundle did batch dids.txt`,
42
+
plcbundle-go did batch dids.txt`,
43
43
}
44
44
45
45
// Add subcommands
···
76
76
Requires DID index to be built.`,
77
77
78
78
Example: ` # Lookup by DID
79
-
plcbundle did lookup did:plc:524tuhdhh3m7li5gycdn6boe
79
+
plcbundle-go did lookup did:plc:524tuhdhh3m7li5gycdn6boe
80
80
81
81
# Lookup by handle
82
-
plcbundle did lookup tree.fail
83
-
plcbundle did lookup ngerakines.me
82
+
plcbundle-go did lookup tree.fail
83
+
plcbundle-go did lookup ngerakines.me
84
84
85
85
# With non-default handle resolver configured
86
86
plcbundle --handle-resolver https://quickdid.smokesignal.tools did lookup tree.fail`,
···
105
105
106
106
stats := mgr.GetDIDIndexStats()
107
107
if !stats["exists"].(bool) {
108
-
fmt.Fprintf(os.Stderr, "โ ๏ธ DID index not found. Run: plcbundle index build\n")
108
+
fmt.Fprintf(os.Stderr, "โ ๏ธ DID index not found. Run: plcbundle-go index build\n")
109
109
fmt.Fprintf(os.Stderr, " Falling back to full scan (slow)...\n\n")
110
110
}
111
111
···
175
175
O(1) lookup of latest operation.`,
176
176
177
177
Example: ` # Resolve DID
178
-
plcbundle did resolve did:plc:524tuhdhh3m7li5gycdn6boe
178
+
plcbundle-go did resolve did:plc:524tuhdhh3m7li5gycdn6boe
179
179
180
180
# Show timings and other details
181
-
plcbundle did resolve did:plc:524tuhdhh3m7li5gycdn6boe --verbose
181
+
plcbundle-go did resolve did:plc:524tuhdhh3m7li5gycdn6boe --verbose
182
182
183
183
# Get raw PLC state (not W3C format)
184
-
plcbundle did resolve did:plc:524tuhdhh3m7li5gycdn6boe --raw
184
+
plcbundle-go did resolve did:plc:524tuhdhh3m7li5gycdn6boe --raw
185
185
186
186
# Pipe to jq
187
-
plcbundle did resolve did:plc:524tuhdhh3m7li5gycdn6boe | jq .service
187
+
plcbundle-go did resolve did:plc:524tuhdhh3m7li5gycdn6boe | jq .service
188
188
189
189
# Resolve by handle
190
-
plcbundle did resolve tree.fail`,
190
+
plcbundle-go did resolve tree.fail`,
191
191
192
192
Args: cobra.ExactArgs(1),
193
193
···
272
272
This provides a full audit trail of all changes to the DID.`,
273
273
274
274
Example: ` # Show full history
275
-
plcbundle did history did:plc:524tuhdhh3m7li5gycdn6boe
275
+
plcbundle-go did history did:plc:524tuhdhh3m7li5gycdn6boe
276
276
277
277
# Include nullified operations
278
-
plcbundle did history did:plc:524tuhdhh3m7li5gycdn6boe --include-nullified
278
+
plcbundle-go did history did:plc:524tuhdhh3m7li5gycdn6boe --include-nullified
279
279
280
280
# Compact one-line format
281
-
plcbundle did history did:plc:524tuhdhh3m7li5gycdn6boe --compact
281
+
plcbundle-go did history did:plc:524tuhdhh3m7li5gycdn6boe --compact
282
282
283
283
# JSON output
284
-
plcbundle did history did:plc:524tuhdhh3m7li5gycdn6boe --json`,
284
+
plcbundle-go did history did:plc:524tuhdhh3m7li5gycdn6boe --json`,
285
285
286
286
Args: cobra.ExactArgs(1),
287
287
···
360
360
- Omit file + use --stdin: reads from stdin`,
361
361
362
362
Example: ` # Batch lookup from file
363
-
plcbundle did batch dids.txt --action lookup
363
+
plcbundle-go did batch dids.txt --action lookup
364
364
365
365
# Read from stdin
366
-
cat dids.txt | plcbundle did batch --stdin --action lookup
367
-
cat dids.txt | plcbundle did batch - --action resolve
366
+
cat dids.txt | plcbundle-go did batch --stdin --action lookup
367
+
cat dids.txt | plcbundle-go did batch - --action resolve
368
368
369
369
# Export operations for DIDs from stdin
370
-
echo "did:plc:524tuhdhh3m7li5gycdn6boe" | plcbundle did batch - --action export
370
+
echo "did:plc:524tuhdhh3m7li5gycdn6boe" | plcbundle-go did batch - --action export
371
371
372
372
# Pipe results
373
-
plcbundle did batch dids.txt --action resolve -o resolved.jsonl
373
+
plcbundle-go did batch dids.txt --action resolve -o resolved.jsonl
374
374
375
375
# Parallel processing
376
-
cat dids.txt | plcbundle did batch --stdin --action lookup --workers 8
376
+
cat dids.txt | plcbundle-go did batch --stdin --action lookup --workers 8
377
377
378
378
# Chain commands
379
-
grep "did:plc:" some_file.txt | plcbundle did batch - --action export > ops.jsonl`,
379
+
grep "did:plc:" some_file.txt | plcbundle-go did batch - --action export > ops.jsonl`,
380
380
381
381
Args: cobra.MaximumNArgs(1),
382
382
···
392
392
} else if !fromStdin {
393
393
return fmt.Errorf("either provide filename or use --stdin flag\n" +
394
394
"Examples:\n" +
395
-
" plcbundle did batch dids.txt\n" +
396
-
" plcbundle did batch --stdin\n" +
397
-
" cat dids.txt | plcbundle did batch -")
395
+
" plcbundle-go did batch dids.txt\n" +
396
+
" plcbundle-go did batch --stdin\n" +
397
+
" cat dids.txt | plcbundle-go did batch -")
398
398
}
399
399
400
400
mgr, _, err := getManager(&ManagerOptions{Cmd: cmd})
···
441
441
Without DID: shows global index statistics`,
442
442
443
443
Example: ` # Stats for specific DID
444
-
plcbundle did stats did:plc:524tuhdhh3m7li5gycdn6boe
444
+
plcbundle-go did stats did:plc:524tuhdhh3m7li5gycdn6boe
445
445
446
446
# Global index stats
447
-
plcbundle did stats --global
448
-
plcbundle did stats
447
+
plcbundle-go did stats --global
448
+
plcbundle-go did stats
449
449
450
450
# JSON output
451
-
plcbundle did stats did:plc:524tuhdhh3m7li5gycdn6boe --json`,
451
+
plcbundle-go did stats did:plc:524tuhdhh3m7li5gycdn6boe --json`,
452
452
453
453
Args: cobra.MaximumNArgs(1),
454
454
···
573
573
574
574
if !stats["exists"].(bool) {
575
575
fmt.Printf("DID index does not exist\n")
576
-
fmt.Printf("Run: plcbundle index build\n")
576
+
fmt.Printf("Run: plcbundle-go index build\n")
577
577
return nil
578
578
}
579
579
+10
-10
cmd/plcbundle/commands/diff.go
+10
-10
cmd/plcbundle/commands/diff.go
···
11
11
12
12
"github.com/goccy/go-json"
13
13
"github.com/spf13/cobra"
14
-
"tangled.org/atscan.net/plcbundle/bundle"
15
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
16
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
14
+
"tangled.org/atscan.net/plcbundle-go/bundle"
15
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
16
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
17
17
)
18
18
19
19
func NewDiffCommand() *cobra.Command {
···
45
45
โข Local file path (e.g., /path/to/plc_bundles.json)`,
46
46
47
47
Example: ` # High-level comparison
48
-
plcbundle diff https://plc.example.com
48
+
plcbundle-go diff https://plc.example.com
49
49
50
50
# Show all differences (verbose)
51
-
plcbundle diff https://plc.example.com -v
51
+
plcbundle-go diff https://plc.example.com -v
52
52
53
53
# Deep dive into specific bundle
54
-
plcbundle diff https://plc.example.com --bundle 23
54
+
plcbundle-go diff https://plc.example.com --bundle 23
55
55
56
56
# Compare bundle with operation samples
57
-
plcbundle diff https://plc.example.com --bundle 23 --show-operations
57
+
plcbundle-go diff https://plc.example.com --bundle 23 --show-operations
58
58
59
59
# Show first 50 operations
60
-
plcbundle diff https://plc.example.com --bundle 23 --sample 50
60
+
plcbundle-go diff https://plc.example.com --bundle 23 --sample 50
61
61
62
62
# Using alias
63
-
plcbundle compare https://plc.example.com`,
63
+
plcbundle-go compare https://plc.example.com`,
64
64
65
65
Args: cobra.ExactArgs(1),
66
66
···
116
116
// If there are hash mismatches, suggest deep dive
117
117
if len(comparison.HashMismatches) > 0 {
118
118
fmt.Printf("\n๐ก Tip: Use --bundle flag to investigate specific mismatches:\n")
119
-
fmt.Printf(" plcbundle diff %s --bundle %d --show-operations\n",
119
+
fmt.Printf(" plcbundle-go diff %s --bundle %d --show-operations\n",
120
120
target, comparison.HashMismatches[0].BundleNumber)
121
121
}
122
122
+153
-333
cmd/plcbundle/commands/export.go
+153
-333
cmd/plcbundle/commands/export.go
···
3
3
import (
4
4
"context"
5
5
"fmt"
6
-
"io"
7
6
"os"
8
7
"time"
9
8
10
9
"github.com/goccy/go-json"
11
10
"github.com/spf13/cobra"
12
-
plcbundle "tangled.org/atscan.net/plcbundle-rs/bindings/go"
13
-
"tangled.org/atscan.net/plcbundle/bundle"
14
-
internalsync "tangled.org/atscan.net/plcbundle/internal/sync"
11
+
internalsync "tangled.org/atscan.net/plcbundle-go/internal/sync"
15
12
)
16
13
17
14
func NewExportCommand() *cobra.Command {
···
39
36
Supports filtering by count and timestamp for selective exports.`,
40
37
41
38
Example: ` # Export all existing bundles
42
-
plcbundle export --all
39
+
plcbundle-go export --all
43
40
44
41
# Export and sync new bundles
45
-
plcbundle export --all --sync
42
+
plcbundle-go export --all --sync
46
43
47
44
# Export specific range (existing only)
48
-
plcbundle export --range 1-100
45
+
plcbundle-go export --range 1-100
49
46
50
47
# Export with limit
51
-
plcbundle export --all --count 50000
48
+
plcbundle-go export --all --count 50000
52
49
53
50
# Export after timestamp
54
-
plcbundle export --all --after 2024-01-01T00:00:00Z
51
+
plcbundle-go export --all --after 2024-01-01T00:00:00Z
55
52
56
53
# Combine filters
57
-
plcbundle export --range 1-100 --count 10000 --after 2024-01-01T00:00:00Z
54
+
plcbundle-go export --range 1-100 --count 10000 --after 2024-01-01T00:00:00Z
58
55
59
56
# Export from specific PLC directory
60
-
plcbundle export --all --sync --plc https://plc.directory
57
+
plcbundle-go export --all --sync --plc https://plc.directory
61
58
62
59
# Pipe to file
63
-
plcbundle export --all > operations.jsonl
60
+
plcbundle-go export --all > operations.jsonl
64
61
65
62
# Process with jq
66
-
plcbundle export --all | jq -r .did | sort | uniq -c
63
+
plcbundle-go export --all | jq -r .did | sort | uniq -c
67
64
68
65
# Sync and filter with detector
69
-
plcbundle export --all --sync | plcbundle detector filter spam
66
+
plcbundle-go export --all --sync | plcbundle-go detector filter spam
70
67
71
68
# Using aliases (backwards compatible)
72
-
plcbundle stream --all --sync
73
-
plcbundle backfill --all`,
69
+
plcbundle-go stream --all --sync
70
+
plcbundle-go backfill --all`,
74
71
75
72
RunE: func(cmd *cobra.Command, args []string) error {
73
+
verbose, _ := cmd.Root().PersistentFlags().GetBool("verbose")
74
+
quiet, _ := cmd.Root().PersistentFlags().GetBool("quiet")
75
+
76
76
mgr, dir, err := getManager(&ManagerOptions{Cmd: cmd, PLCURL: plcURL})
77
77
if err != nil {
78
78
return err
79
79
}
80
80
defer mgr.Close()
81
81
82
-
verbose, quiet := getVerboseQuiet(cmd)
83
-
return runExport(cmd.Context(), mgr, dir, exportFlags{
84
-
all: all,
85
-
rangeStr: rangeStr,
86
-
sync: sync,
87
-
count: count,
88
-
after: after,
89
-
verbose: verbose,
90
-
quiet: quiet,
91
-
})
92
-
},
93
-
}
82
+
if !quiet {
83
+
fmt.Fprintf(os.Stderr, "Exporting from: %s\n", dir)
84
+
}
94
85
95
-
cmd.Flags().BoolVar(&all, "all", false, "Export all bundles")
96
-
cmd.Flags().StringVarP(&rangeStr, "range", "r", "", "Export bundle range (e.g., '1-100')")
97
-
cmd.Flags().BoolVar(&sync, "sync", false, "Also fetch new bundles from PLC (until caught up)")
98
-
cmd.Flags().StringVar(&plcURL, "plc", "https://plc.directory", "PLC directory URL (for --sync)")
99
-
cmd.Flags().IntVarP(&count, "count", "n", 0, "Limit number of operations (0 = unlimited)")
100
-
cmd.Flags().StringVar(&after, "after", "", "Only export operations after this timestamp (RFC3339)")
86
+
// Parse after timestamp if provided
87
+
var afterTime time.Time
88
+
if after != "" {
89
+
afterTime, err = time.Parse(time.RFC3339, after)
90
+
if err != nil {
91
+
return fmt.Errorf("invalid --after timestamp (use RFC3339 format): %w", err)
92
+
}
93
+
}
101
94
102
-
return cmd
103
-
}
95
+
// Determine bundle range
96
+
var start, end int
104
97
105
-
type exportFlags struct {
106
-
all bool
107
-
rangeStr string
108
-
sync bool
109
-
count int
110
-
after string
111
-
verbose bool
112
-
quiet bool
113
-
}
98
+
if all {
99
+
index := mgr.GetIndex()
100
+
bundles := index.GetBundles()
114
101
115
-
type exportOptions struct {
116
-
start int
117
-
end int
118
-
exportAll bool
119
-
sync bool
120
-
count int
121
-
afterTimestamp string
122
-
verbose bool
123
-
quiet bool
124
-
}
102
+
if len(bundles) == 0 {
103
+
if sync {
104
+
// No bundles but sync enabled - start from 1
105
+
start = 1
106
+
end = 0 // Will be updated after sync
107
+
} else {
108
+
if !quiet {
109
+
fmt.Fprintf(os.Stderr, "No bundles available (use --sync to fetch)\n")
110
+
}
111
+
return nil
112
+
}
113
+
} else {
114
+
start = bundles[0].BundleNumber
115
+
end = bundles[len(bundles)-1].BundleNumber
116
+
}
125
117
126
-
// runExport performs the export operation
127
-
func runExport(ctx context.Context, mgr BundleManager, dir string, flags exportFlags) error {
128
-
// Parse after timestamp if provided
129
-
var afterTimestamp string
130
-
if flags.after != "" {
131
-
afterTime, err := time.Parse(time.RFC3339, flags.after)
132
-
if err != nil {
133
-
return fmt.Errorf("invalid --after timestamp (use RFC3339 format): %w", err)
134
-
}
135
-
afterTimestamp = afterTime.Format(time.RFC3339)
136
-
}
118
+
} else if rangeStr != "" {
119
+
var err error
120
+
start, end, err = parseBundleRange(rangeStr)
121
+
if err != nil {
122
+
return err
123
+
}
137
124
138
-
// Determine bundle range
139
-
var start, end uint32
140
-
var exportAll bool
125
+
} else {
126
+
return fmt.Errorf("either --all or --range required")
127
+
}
141
128
142
-
if flags.all {
143
-
index := mgr.GetIndex()
144
-
bundles := index.GetBundles()
129
+
if !quiet {
130
+
if sync {
131
+
fmt.Fprintf(os.Stderr, "Mode: export existing + sync new bundles\n")
132
+
} else {
133
+
fmt.Fprintf(os.Stderr, "Mode: export existing only\n")
134
+
}
145
135
146
-
if len(bundles) == 0 {
147
-
if flags.sync {
148
-
// No bundles but sync enabled - start from 1
149
-
start = 1
150
-
end = 0 // Will be updated after sync
151
-
exportAll = false
152
-
} else {
153
-
if !flags.quiet {
154
-
fmt.Fprintf(os.Stderr, "No bundles available (use --sync to fetch)\n")
136
+
if count > 0 {
137
+
fmt.Fprintf(os.Stderr, "Limit: %d operations\n", count)
138
+
}
139
+
if after != "" {
140
+
fmt.Fprintf(os.Stderr, "After: %s\n", after)
155
141
}
156
-
return nil
142
+
fmt.Fprintf(os.Stderr, "\n")
157
143
}
158
-
} else {
159
-
if flags.sync {
160
-
// Export existing bundles, then sync
161
-
start = uint32(bundles[0].BundleNumber)
162
-
end = uint32(bundles[len(bundles)-1].BundleNumber)
163
-
exportAll = false
164
-
} else {
165
-
// For export only, use export_all flag
166
-
exportAll = true
167
-
start = 0
168
-
end = 0
169
-
}
170
-
}
171
144
172
-
} else if flags.rangeStr != "" {
173
-
var err error
174
-
startInt, endInt, err := parseBundleRange(flags.rangeStr)
175
-
if err != nil {
176
-
return err
177
-
}
178
-
start = uint32(startInt)
179
-
end = uint32(endInt)
180
-
exportAll = false
181
-
182
-
} else {
183
-
return fmt.Errorf("either --all or --range required")
184
-
}
185
-
186
-
opts := exportOptions{
187
-
start: int(start),
188
-
end: int(end),
189
-
exportAll: exportAll,
190
-
sync: flags.sync,
191
-
count: flags.count,
192
-
afterTimestamp: afterTimestamp,
193
-
verbose: flags.verbose,
194
-
quiet: flags.quiet,
195
-
}
196
-
197
-
if !flags.quiet {
198
-
fmt.Fprintf(os.Stderr, "Exporting from: %s\n", dir)
199
-
if flags.sync {
200
-
fmt.Fprintf(os.Stderr, "Mode: export existing + sync new bundles\n")
201
-
} else {
202
-
fmt.Fprintf(os.Stderr, "Mode: export existing only (using Rust library)\n")
203
-
}
204
-
205
-
if flags.count > 0 {
206
-
fmt.Fprintf(os.Stderr, "Limit: %d operations\n", flags.count)
207
-
}
208
-
if flags.after != "" {
209
-
fmt.Fprintf(os.Stderr, "After: %s\n", flags.after)
210
-
}
211
-
fmt.Fprintf(os.Stderr, "\n")
145
+
return exportBundles(cmd.Context(), mgr, exportOptions{
146
+
start: start,
147
+
end: end,
148
+
sync: sync,
149
+
count: count,
150
+
afterTime: afterTime,
151
+
verbose: verbose,
152
+
quiet: quiet,
153
+
})
154
+
},
212
155
}
213
156
214
-
return exportBundles(ctx, mgr, opts)
215
-
}
157
+
cmd.Flags().BoolVar(&all, "all", false, "Export all bundles")
158
+
cmd.Flags().StringVarP(&rangeStr, "range", "r", "", "Export bundle range (e.g., '1-100')")
159
+
cmd.Flags().BoolVar(&sync, "sync", false, "Also fetch new bundles from PLC (until caught up)")
160
+
cmd.Flags().StringVar(&plcURL, "plc", "https://plc.directory", "PLC directory URL (for --sync)")
161
+
cmd.Flags().IntVarP(&count, "count", "n", 0, "Limit number of operations (0 = unlimited)")
162
+
cmd.Flags().StringVar(&after, "after", "", "Only export operations after this timestamp (RFC3339)")
216
163
217
-
// ExportSpec defines export parameters
218
-
type ExportSpec struct {
219
-
BundleStart uint32
220
-
BundleEnd uint32
221
-
ExportAll bool
222
-
CountLimit uint64
223
-
AfterTimestamp string
224
-
DIDFilter string
225
-
OpTypeFilter string
164
+
return cmd
226
165
}
227
166
228
-
// ExportStats contains export statistics
229
-
type ExportStats struct {
230
-
RecordsWritten uint64
231
-
BytesWritten uint64
232
-
BundlesProcessed int
167
+
type exportOptions struct {
168
+
start int
169
+
end int
170
+
sync bool
171
+
count int
172
+
afterTime time.Time
173
+
verbose bool
174
+
quiet bool
233
175
}
234
176
235
-
// exportBundles exports bundles using the Rust library via Manager proxy
236
177
func exportBundles(ctx context.Context, mgr BundleManager, opts exportOptions) error {
237
-
// Phase 1: Export existing bundles
238
-
var exported uint64
239
-
var existingCount int
240
-
241
-
if opts.exportAll || opts.end > 0 {
242
-
// Build export spec
243
-
spec := ExportSpec{
244
-
BundleStart: uint32(opts.start),
245
-
BundleEnd: uint32(opts.end),
246
-
ExportAll: opts.exportAll,
247
-
CountLimit: uint64(opts.count),
248
-
AfterTimestamp: opts.afterTimestamp,
249
-
DIDFilter: "", // Not supported in current flags
250
-
OpTypeFilter: "", // Not supported in current flags
251
-
}
252
-
253
-
// Progress callback
254
-
var progressCallback func(records, bytes uint64)
255
-
if !opts.quiet {
256
-
progressCallback = func(records, bytes uint64) {
257
-
if opts.verbose {
258
-
fmt.Fprintf(os.Stderr, "Progress: %d records, %s\r", records, formatBytes(int64(bytes)))
259
-
} else if records%10000 == 0 {
260
-
fmt.Fprintf(os.Stderr, "Exported: %d records\r", records)
261
-
}
262
-
}
263
-
}
264
-
265
-
// Get Rust manager from bundle manager
266
-
concreteMgr := mgr.(*bundle.Manager)
267
-
rsMgr, err := concreteMgr.GetRSManager()
268
-
if err != nil {
269
-
// Fallback to Go implementation if Rust manager unavailable
270
-
return exportToWriterGo(ctx, concreteMgr, spec, os.Stdout, progressCallback, &exported, &existingCount)
271
-
}
272
-
273
-
// Convert to Rust export spec
274
-
rsSpec := plcbundle.ExportSpec{
275
-
BundleStart: spec.BundleStart,
276
-
BundleEnd: spec.BundleEnd,
277
-
ExportAll: spec.ExportAll,
278
-
Format: 0, // 0 = jsonl
279
-
CountLimit: spec.CountLimit,
280
-
AfterTimestamp: spec.AfterTimestamp,
281
-
DIDFilter: spec.DIDFilter,
282
-
OpTypeFilter: spec.OpTypeFilter,
283
-
}
284
-
285
-
// Export options
286
-
rsOpts := &plcbundle.ExportOptions{
287
-
Writer: os.Stdout,
288
-
Progress: progressCallback,
289
-
}
290
-
291
-
// Perform export using Rust library
292
-
rsStats, err := rsMgr.Export(rsSpec, rsOpts)
293
-
if err != nil {
294
-
return fmt.Errorf("export failed: %w", err)
295
-
}
296
-
297
-
exported = rsStats.RecordsWritten
178
+
operationCount := 0
179
+
exported := 0
298
180
299
-
// Calculate bundle count
300
-
if !spec.ExportAll && spec.BundleEnd >= spec.BundleStart {
301
-
existingCount = int(spec.BundleEnd - spec.BundleStart + 1)
302
-
} else if spec.ExportAll {
303
-
index := mgr.GetIndex()
304
-
bundles := index.GetBundles()
305
-
existingCount = len(bundles)
306
-
}
181
+
// Phase 1: Export existing bundles
182
+
existingCount := 0
183
+
if opts.end > 0 {
184
+
existingCount, exported = exportExistingBundles(
185
+
ctx, mgr, opts.start, opts.end,
186
+
&operationCount, opts.count, opts.afterTime,
187
+
opts.verbose, opts.quiet,
188
+
)
307
189
}
308
190
309
191
// Check if we hit the count limit
310
-
if opts.count > 0 && exported >= uint64(opts.count) {
192
+
if opts.count > 0 && exported >= opts.count {
311
193
if !opts.quiet {
312
194
fmt.Fprintf(os.Stderr, "\nโ Export complete (limit reached)\n")
313
-
if existingCount > 0 {
314
-
fmt.Fprintf(os.Stderr, " Bundles: %d\n", existingCount)
315
-
}
195
+
fmt.Fprintf(os.Stderr, " Bundles: %d\n", existingCount)
316
196
fmt.Fprintf(os.Stderr, " Operations: %d\n", exported)
317
197
}
318
198
return nil
···
320
200
321
201
// Phase 2: Sync and export new bundles (if enabled and not at limit)
322
202
fetchedCount := 0
323
-
if opts.sync && (opts.count == 0 || exported < uint64(opts.count)) {
203
+
if opts.sync && (opts.count == 0 || exported < opts.count) {
324
204
if !opts.quiet {
325
205
fmt.Fprintf(os.Stderr, "\nSyncing new bundles from PLC...\n")
326
206
}
···
335
215
if bundle, err := mgr.LoadBundle(ctx, bundleNum); err == nil {
336
216
for _, op := range bundle.Operations {
337
217
// Apply filters
338
-
if opts.afterTimestamp != "" {
339
-
opTime := op.CreatedAt.Format(time.RFC3339)
340
-
if opTime < opts.afterTimestamp {
341
-
continue
342
-
}
218
+
if !opts.afterTime.IsZero() && op.CreatedAt.Before(opts.afterTime) {
219
+
continue
343
220
}
344
221
345
-
if opts.count > 0 && exported >= uint64(opts.count) {
222
+
if opts.count > 0 && exported >= opts.count {
346
223
return // Stop when limit reached
347
224
}
348
225
···
354
231
fmt.Println(string(data))
355
232
}
356
233
exported++
234
+
operationCount++
357
235
}
358
236
}
359
237
},
···
375
253
existingCount+fetchedCount, existingCount, fetchedCount)
376
254
} else if opts.sync {
377
255
fmt.Fprintf(os.Stderr, " Bundles: %d (already up to date)\n", existingCount)
378
-
} else if existingCount > 0 {
256
+
} else {
379
257
fmt.Fprintf(os.Stderr, " Bundles: %d\n", existingCount)
380
258
}
381
259
···
389
267
return nil
390
268
}
391
269
392
-
// exportToWriterGo is the fallback Go implementation
393
-
func exportToWriterGo(ctx context.Context, mgr *bundle.Manager, spec ExportSpec, writer io.Writer, progress func(records, bytes uint64), exported *uint64, existingCount *int) error {
394
-
var recordsWritten uint64
395
-
var bytesWritten uint64
396
-
var bundlesProcessed int
270
+
func exportExistingBundles(
271
+
ctx context.Context,
272
+
mgr BundleManager,
273
+
start, end int,
274
+
operationCount *int,
275
+
limit int,
276
+
afterTime time.Time,
277
+
verbose bool,
278
+
quiet bool,
279
+
) (bundleCount int, exported int) {
397
280
398
-
bundles := mgr.GetIndex().GetBundles()
399
-
if len(bundles) == 0 {
400
-
*exported = 0
401
-
*existingCount = 0
402
-
return nil
403
-
}
281
+
processedCount := 0
282
+
exportedOps := 0
404
283
405
-
// Determine bundle range
406
-
startBundle := 0
407
-
endBundle := len(bundles) - 1
408
-
409
-
if spec.ExportAll {
410
-
startBundle = 0
411
-
endBundle = len(bundles) - 1
412
-
} else {
413
-
// Find start and end indices
414
-
startBundle = -1
415
-
endBundle = -1
416
-
for i, b := range bundles {
417
-
if startBundle == -1 && b.BundleNumber >= int(spec.BundleStart) {
418
-
startBundle = i
419
-
}
420
-
if b.BundleNumber <= int(spec.BundleEnd) {
421
-
endBundle = i
422
-
}
423
-
}
424
-
if startBundle == -1 || endBundle == -1 || startBundle > endBundle {
425
-
*exported = 0
426
-
*existingCount = 0
427
-
return nil
428
-
}
429
-
}
430
-
431
-
// Parse after timestamp
432
-
var afterTime time.Time
433
-
if spec.AfterTimestamp != "" {
434
-
var err error
435
-
afterTime, err = time.Parse(time.RFC3339, spec.AfterTimestamp)
436
-
if err != nil {
437
-
return fmt.Errorf("invalid after timestamp: %w", err)
438
-
}
439
-
}
440
-
441
-
// Export bundles
442
-
for i := startBundle; i <= endBundle; i++ {
284
+
for bundleNum := start; bundleNum <= end; bundleNum++ {
443
285
select {
444
286
case <-ctx.Done():
445
-
*exported = recordsWritten
446
-
*existingCount = bundlesProcessed
447
-
return ctx.Err()
287
+
return processedCount, exportedOps
448
288
default:
449
289
}
450
290
451
-
meta := bundles[i]
452
-
bundle, err := mgr.LoadBundle(ctx, meta.BundleNumber)
291
+
bundle, err := mgr.LoadBundle(ctx, bundleNum)
453
292
if err != nil {
293
+
if verbose {
294
+
fmt.Fprintf(os.Stderr, "Bundle %06d: not found (skipped)\n", bundleNum)
295
+
}
454
296
continue
455
297
}
456
298
457
-
// Export operations
299
+
// Export operations with filters
458
300
for _, op := range bundle.Operations {
459
-
// Apply filters
301
+
// Filter by timestamp
460
302
if !afterTime.IsZero() && op.CreatedAt.Before(afterTime) {
461
303
continue
462
304
}
463
-
if spec.DIDFilter != "" && op.DID != spec.DIDFilter {
464
-
continue
465
-
}
466
-
if spec.OpTypeFilter != "" {
467
-
// Operation type is inside the parsed operation data
468
-
opData, err := op.GetOperationData()
469
-
if err == nil && opData != nil {
470
-
if opType, ok := opData["type"].(string); ok && opType != spec.OpTypeFilter {
471
-
continue
472
-
} else if !ok {
473
-
continue // Skip if no type field
474
-
}
475
-
} else {
476
-
continue // Skip if can't parse
305
+
306
+
// Check count limit
307
+
if limit > 0 && exportedOps >= limit {
308
+
if verbose {
309
+
fmt.Fprintf(os.Stderr, "Bundle %06d: limit reached, stopping\n", bundleNum)
477
310
}
478
-
}
479
-
if spec.CountLimit > 0 && recordsWritten >= spec.CountLimit {
480
-
*exported = recordsWritten
481
-
*existingCount = bundlesProcessed
482
-
return nil
311
+
return processedCount, exportedOps
483
312
}
484
313
485
-
// Write operation
486
-
var data []byte
314
+
// Output operation to stdout (JSONL)
487
315
if len(op.RawJSON) > 0 {
488
-
data = op.RawJSON
316
+
fmt.Println(string(op.RawJSON))
489
317
} else {
490
-
var err error
491
-
data, err = json.Marshal(op)
492
-
if err != nil {
493
-
continue
494
-
}
495
-
}
496
-
data = append(data, '\n')
497
-
498
-
if _, err := writer.Write(data); err != nil {
499
-
return fmt.Errorf("write failed: %w", err)
318
+
data, _ := json.Marshal(op)
319
+
fmt.Println(string(data))
500
320
}
321
+
exportedOps++
322
+
}
501
323
502
-
recordsWritten++
503
-
bytesWritten += uint64(len(data))
324
+
*operationCount += len(bundle.Operations)
325
+
processedCount++
504
326
505
-
if progress != nil && recordsWritten%1000 == 0 {
506
-
progress(recordsWritten, bytesWritten)
507
-
}
327
+
if verbose {
328
+
fmt.Fprintf(os.Stderr, "Bundle %06d: โ (%d ops, %d exported)\n",
329
+
bundleNum, len(bundle.Operations), exportedOps)
330
+
} else if !quiet && processedCount%100 == 0 {
331
+
fmt.Fprintf(os.Stderr, "Exported: %d bundles, %d ops\r", processedCount, exportedOps)
508
332
}
509
-
510
-
bundlesProcessed++
511
333
}
512
334
513
-
if progress != nil {
514
-
progress(recordsWritten, bytesWritten)
335
+
if !quiet && !verbose && processedCount > 0 {
336
+
fmt.Fprintf(os.Stderr, "Existing: %d bundles, %d ops\n", processedCount, exportedOps)
515
337
}
516
338
517
-
*exported = recordsWritten
518
-
*existingCount = bundlesProcessed
519
-
return nil
339
+
return processedCount, exportedOps
520
340
}
521
341
522
342
type exportLogger struct {
+16
-16
cmd/plcbundle/commands/index.go
+16
-16
cmd/plcbundle/commands/index.go
···
7
7
8
8
"github.com/goccy/go-json"
9
9
"github.com/spf13/cobra"
10
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/ui"
10
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/ui"
11
11
)
12
12
13
13
func NewIndexCommand() *cobra.Command {
···
21
21
resolution and query operations.`,
22
22
23
23
Example: ` # Build DID position index
24
-
plcbundle index build
24
+
plcbundle-go index build
25
25
26
26
# Repair DID index (rebuild from bundles)
27
-
plcbundle index repair
27
+
plcbundle-go index repair
28
28
29
29
# Show DID index statistics
30
-
plcbundle index stats
30
+
plcbundle-go index stats
31
31
32
32
# Verify DID index integrity
33
-
plcbundle index verify`,
33
+
plcbundle-go index verify`,
34
34
}
35
35
36
36
cmd.AddCommand(newIndexBuildCommand())
···
60
60
are added. Use --force to rebuild from scratch.`,
61
61
62
62
Example: ` # Build index
63
-
plcbundle index build
63
+
plcbundle-go index build
64
64
65
65
# Force rebuild from scratch
66
-
plcbundle index build --force`,
66
+
plcbundle-go index build --force`,
67
67
68
68
RunE: func(cmd *cobra.Command, args []string) error {
69
69
mgr, dir, err := getManager(&ManagerOptions{Cmd: cmd})
···
141
141
โข Upgrade to new index version`,
142
142
143
143
Example: ` # Repair DID index
144
-
plcbundle index repair
144
+
plcbundle-go index repair
145
145
146
146
# Verbose output
147
-
plcbundle index repair -v`,
147
+
plcbundle-go index repair -v`,
148
148
149
149
RunE: func(cmd *cobra.Command, args []string) error {
150
150
verbose, _ := cmd.Root().PersistentFlags().GetBool("verbose")
···
158
158
stats := mgr.GetDIDIndexStats()
159
159
if !stats["exists"].(bool) {
160
160
fmt.Printf("DID index does not exist\n")
161
-
fmt.Printf("Use: plcbundle index build\n")
161
+
fmt.Printf("Use: plcbundle-go index build\n")
162
162
return nil
163
163
}
164
164
···
237
237
shard distribution, cache statistics, and coverage.`,
238
238
239
239
Example: ` # Show statistics
240
-
plcbundle index stats
240
+
plcbundle-go index stats
241
241
242
242
# JSON output
243
-
plcbundle index stats --json`,
243
+
plcbundle-go index stats --json`,
244
244
245
245
RunE: func(cmd *cobra.Command, args []string) error {
246
246
mgr, dir, err := getManager(&ManagerOptions{Cmd: cmd})
···
259
259
260
260
if !stats["exists"].(bool) {
261
261
fmt.Printf("DID index does not exist\n")
262
-
fmt.Printf("Run: plcbundle index build\n")
262
+
fmt.Printf("Run: plcbundle-go index build\n")
263
263
return nil
264
264
}
265
265
···
332
332
Automatically repairs minor issues.`,
333
333
334
334
Example: ` # Verify DID index
335
-
plcbundle index verify
335
+
plcbundle-go index verify
336
336
337
337
# Verbose output
338
-
plcbundle index verify -v`,
338
+
plcbundle-go index verify -v`,
339
339
340
340
RunE: func(cmd *cobra.Command, args []string) error {
341
341
mgr, dir, err := getManager(&ManagerOptions{Cmd: cmd})
···
348
348
349
349
if !stats["exists"].(bool) {
350
350
fmt.Printf("DID index does not exist\n")
351
-
fmt.Printf("Run: plcbundle index build\n")
351
+
fmt.Printf("Run: plcbundle-go index build\n")
352
352
return nil
353
353
}
354
354
+8
-8
cmd/plcbundle/commands/inspect.go
+8
-8
cmd/plcbundle/commands/inspect.go
···
11
11
12
12
"github.com/goccy/go-json"
13
13
"github.com/spf13/cobra"
14
-
"tangled.org/atscan.net/plcbundle/internal/storage"
14
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
15
15
)
16
16
17
17
// ============================================================================
···
178
178
Can inspect either by bundle number (from repository) or direct file path.`,
179
179
180
180
Example: ` # Inspect from repository
181
-
plcbundle inspect 42
181
+
plcbundle-go inspect 42
182
182
183
183
# Inspect specific file
184
-
plcbundle inspect /path/to/000042.jsonl.zst
185
-
plcbundle inspect 000042.jsonl.zst
184
+
plcbundle-go inspect /path/to/000042.jsonl.zst
185
+
plcbundle-go inspect 000042.jsonl.zst
186
186
187
187
# Skip certain analysis sections
188
-
plcbundle inspect 42 --skip-patterns --skip-crypto
188
+
plcbundle-go inspect 42 --skip-patterns --skip-crypto
189
189
190
190
# Show sample operations
191
-
plcbundle inspect 42 --samples --sample-count 20
191
+
plcbundle-go inspect 42 --samples --sample-count 20
192
192
193
193
# Verify all hashes
194
-
plcbundle inspect 42 --verify
194
+
plcbundle-go inspect 42 --verify
195
195
196
196
# JSON output (for scripting)
197
-
plcbundle inspect 42 --json`,
197
+
plcbundle-go inspect 42 --json`,
198
198
199
199
Args: cobra.ExactArgs(1),
200
200
+12
-12
cmd/plcbundle/commands/log.go
+12
-12
cmd/plcbundle/commands/log.go
···
10
10
11
11
"github.com/spf13/cobra"
12
12
"golang.org/x/term"
13
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
13
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
14
14
)
15
15
16
16
func NewLogCommand() *cobra.Command {
···
43
43
is a terminal, just like 'git log'. Use --no-pager to disable.`,
44
44
45
45
Example: ` # Show all bundles (newest first, auto-paged)
46
-
plcbundle log
46
+
plcbundle-go log
47
47
48
48
# Show last 10 bundles
49
-
plcbundle log --last 10
50
-
plcbundle log -n 10
49
+
plcbundle-go log --last 10
50
+
plcbundle-go log -n 10
51
51
52
52
# One-line format
53
-
plcbundle log --oneline
53
+
plcbundle-go log --oneline
54
54
55
55
# Hide hashes
56
-
plcbundle log --no-hashes
56
+
plcbundle-go log --no-hashes
57
57
58
58
# Oldest first (ascending order)
59
-
plcbundle log --reverse
59
+
plcbundle-go log --reverse
60
60
61
61
# Disable pager (direct output)
62
-
plcbundle log --no-pager
62
+
plcbundle-go log --no-pager
63
63
64
64
# Combination
65
-
plcbundle log -n 20 --oneline
65
+
plcbundle-go log -n 20 --oneline
66
66
67
67
# Using alias
68
-
plcbundle history -n 5`,
68
+
plcbundle-go history -n 5`,
69
69
70
70
RunE: func(cmd *cobra.Command, args []string) error {
71
71
mgr, dir, err := getManager(&ManagerOptions{Cmd: cmd})
···
110
110
fmt.Printf("No bundles in repository\n")
111
111
fmt.Printf("Directory: %s\n\n", dir)
112
112
fmt.Printf("Get started:\n")
113
-
fmt.Printf(" plcbundle clone <url> Clone from remote\n")
114
-
fmt.Printf(" plcbundle sync Fetch from PLC directory\n")
113
+
fmt.Printf(" plcbundle-go clone <url> Clone from remote\n")
114
+
fmt.Printf(" plcbundle-go sync Fetch from PLC directory\n")
115
115
return nil
116
116
}
117
117
+11
-11
cmd/plcbundle/commands/ls.go
+11
-11
cmd/plcbundle/commands/ls.go
···
6
6
"time"
7
7
8
8
"github.com/spf13/cobra"
9
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
9
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
10
10
)
11
11
12
12
func NewLsCommand() *cobra.Command {
···
30
30
shell scripts and automation.`,
31
31
32
32
Example: ` # List all bundles
33
-
plcbundle ls
33
+
plcbundle-go ls
34
34
35
35
# Last 10 bundles
36
-
plcbundle ls -n 10
36
+
plcbundle-go ls -n 10
37
37
38
38
# Oldest first
39
-
plcbundle ls --reverse
39
+
plcbundle-go ls --reverse
40
40
41
41
# Custom format
42
-
plcbundle ls --format "bundle,hash,date,size"
42
+
plcbundle-go ls --format "bundle,hash,date,size"
43
43
44
44
# CSV format
45
-
plcbundle ls --separator ","
45
+
plcbundle-go ls --separator ","
46
46
47
47
# Scripting examples
48
-
plcbundle ls | awk '{print $1}' # Just bundle numbers
49
-
plcbundle ls | grep 000150 # Find specific bundle
50
-
plcbundle ls -n 5 | cut -f1,4 # First and 4th columns
51
-
plcbundle ls --format bundle,hash # Custom columns
52
-
plcbundle ls --separator "," > bundles.csv # Export to CSV`,
48
+
plcbundle-go ls | awk '{print $1}' # Just bundle numbers
49
+
plcbundle-go ls | grep 000150 # Find specific bundle
50
+
plcbundle-go ls -n 5 | cut -f1,4 # First and 4th columns
51
+
plcbundle-go ls --format bundle,hash # Custom columns
52
+
plcbundle-go ls --separator "," > bundles.csv # Export to CSV`,
53
53
54
54
RunE: func(cmd *cobra.Command, args []string) error {
55
55
mgr, _, err := getManager(&ManagerOptions{Cmd: cmd})
+19
-19
cmd/plcbundle/commands/mempool.go
+19
-19
cmd/plcbundle/commands/mempool.go
···
9
9
10
10
"github.com/goccy/go-json"
11
11
"github.com/spf13/cobra"
12
-
"tangled.org/atscan.net/plcbundle/internal/types"
12
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
13
13
)
14
14
15
15
func NewMempoolCommand() *cobra.Command {
···
23
23
strict chronological order and automatically validates consistency.`,
24
24
25
25
Example: ` # Show mempool status
26
-
plcbundle mempool
27
-
plcbundle mempool status
26
+
plcbundle-go mempool
27
+
plcbundle-go mempool status
28
28
29
29
# Clear all operations
30
-
plcbundle mempool clear
30
+
plcbundle-go mempool clear
31
31
32
32
# Export operations as JSONL
33
-
plcbundle mempool dump
34
-
plcbundle mempool dump > operations.jsonl
33
+
plcbundle-go mempool dump
34
+
plcbundle-go mempool dump > operations.jsonl
35
35
36
36
# Using alias
37
-
plcbundle mp status`,
37
+
plcbundle-go mp status`,
38
38
39
39
RunE: func(cmd *cobra.Command, args []string) error {
40
40
// Default to status subcommand
···
67
67
next bundle, validation status, and memory usage.`,
68
68
69
69
Example: ` # Show status
70
-
plcbundle mempool status
71
-
plcbundle mempool
70
+
plcbundle-go mempool status
71
+
plcbundle-go mempool
72
72
73
73
# Verbose output with samples
74
-
plcbundle mempool status -v`,
74
+
plcbundle-go mempool status -v`,
75
75
76
76
RunE: func(cmd *cobra.Command, args []string) error {
77
77
return mempoolStatus(cmd, args)
···
123
123
โข Force fresh start`,
124
124
125
125
Example: ` # Clear with confirmation
126
-
plcbundle mempool clear
126
+
plcbundle-go mempool clear
127
127
128
128
# Force clear without confirmation
129
-
plcbundle mempool clear --force
130
-
plcbundle mempool clear -f`,
129
+
plcbundle-go mempool clear --force
130
+
plcbundle-go mempool clear -f`,
131
131
132
132
RunE: func(cmd *cobra.Command, args []string) error {
133
133
mgr, dir, err := getManager(&ManagerOptions{Cmd: cmd})
···
188
188
Perfect for backup, analysis, or piping to other tools.`,
189
189
190
190
Example: ` # Dump to stdout
191
-
plcbundle mempool dump
191
+
plcbundle-go mempool dump
192
192
193
193
# Save to file
194
-
plcbundle mempool dump > mempool.jsonl
195
-
plcbundle mempool dump -o mempool.jsonl
194
+
plcbundle-go mempool dump > mempool.jsonl
195
+
plcbundle-go mempool dump -o mempool.jsonl
196
196
197
197
# Pipe to jq
198
-
plcbundle mempool dump | jq -r .did
198
+
plcbundle-go mempool dump | jq -r .did
199
199
200
200
# Count operations
201
-
plcbundle mempool dump | wc -l
201
+
plcbundle-go mempool dump | wc -l
202
202
203
203
# Using alias
204
-
plcbundle mempool export`,
204
+
plcbundle-go mempool export`,
205
205
206
206
RunE: func(cmd *cobra.Command, args []string) error {
207
207
mgr, _, err := getManager(&ManagerOptions{Cmd: cmd})
+8
-8
cmd/plcbundle/commands/migrate.go
+8
-8
cmd/plcbundle/commands/migrate.go
···
8
8
"time"
9
9
10
10
"github.com/spf13/cobra"
11
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/ui"
12
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
13
-
"tangled.org/atscan.net/plcbundle/internal/storage"
11
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/ui"
12
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
13
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
14
14
)
15
15
16
16
func NewMigrateCommand() *cobra.Command {
···
41
41
Original files are replaced atomically. Use --dry-run to preview.`,
42
42
43
43
Example: ` # Preview migration (recommended first)
44
-
plcbundle migrate --dry-run
44
+
plcbundle-go migrate --dry-run
45
45
46
46
# Migrate all legacy bundles
47
-
plcbundle migrate
47
+
plcbundle-go migrate
48
48
49
49
# Force migration even if .idx files exist
50
-
plcbundle migrate --force
50
+
plcbundle-go migrate --force
51
51
52
52
# Parallel migration (faster)
53
-
plcbundle migrate --workers 8
53
+
plcbundle-go migrate --workers 8
54
54
55
55
# Verbose output
56
-
plcbundle migrate -v`,
56
+
plcbundle-go migrate -v`,
57
57
58
58
RunE: func(cmd *cobra.Command, args []string) error {
59
59
verbose, _ := cmd.Root().PersistentFlags().GetBool("verbose")
+17
-17
cmd/plcbundle/commands/op.go
+17
-17
cmd/plcbundle/commands/op.go
···
10
10
11
11
"github.com/goccy/go-json"
12
12
"github.com/spf13/cobra"
13
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
14
-
"tangled.org/atscan.net/plcbundle/internal/types"
13
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
14
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
15
15
)
16
16
17
17
func NewOpCommand() *cobra.Command {
···
29
29
Example: 88410345 = bundle 8841, position 345`,
30
30
31
31
Example: ` # Get operation as JSON
32
-
plcbundle op get 42 1337
33
-
plcbundle op get 420000
32
+
plcbundle-go op get 42 1337
33
+
plcbundle-go op get 420000
34
34
35
35
# Show operation (formatted)
36
-
plcbundle op show 42 1337
37
-
plcbundle op show 88410345
36
+
plcbundle-go op show 42 1337
37
+
plcbundle-go op show 88410345
38
38
39
39
# Find by CID
40
-
plcbundle op find bafyreig3...`,
40
+
plcbundle-go op find bafyreig3...`,
41
41
}
42
42
43
43
// Add subcommands
···
69
69
Use -v/--verbose to see detailed timing breakdown.`,
70
70
71
71
Example: ` # By bundle + position
72
-
plcbundle op get 42 1337
72
+
plcbundle-go op get 42 1337
73
73
74
74
# By global position
75
-
plcbundle op get 88410345
75
+
plcbundle-go op get 88410345
76
76
77
77
# With timing metrics
78
-
plcbundle op get 42 1337 -v
79
-
plcbundle op get 88410345 --verbose
78
+
plcbundle-go op get 42 1337 -v
79
+
plcbundle-go op get 88410345 --verbose
80
80
81
81
# Pipe to jq
82
-
plcbundle op get 42 1337 | jq .did`,
82
+
plcbundle-go op get 42 1337 | jq .did`,
83
83
84
84
Args: cobra.RangeArgs(1, 2),
85
85
···
154
154
โข Performance metrics (with -v)`,
155
155
156
156
Example: ` # By bundle + position
157
-
plcbundle op show 42 1337
157
+
plcbundle-go op show 42 1337
158
158
159
159
# By global position
160
-
plcbundle op show 88410345
160
+
plcbundle-go op show 88410345
161
161
162
162
# Verbose with timing and full JSON
163
-
plcbundle op show 42 1337 -v`,
163
+
plcbundle-go op show 42 1337 -v`,
164
164
165
165
Args: cobra.RangeArgs(1, 2),
166
166
···
218
218
Note: This performs a full scan and can be slow on large repositories.`,
219
219
220
220
Example: ` # Find by CID
221
-
plcbundle op find bafyreig3tg4k...
221
+
plcbundle-go op find bafyreig3tg4k...
222
222
223
223
# Pipe to op get
224
-
plcbundle op find bafyreig3... | awk '{print $3, $5}' | xargs plcbundle op get`,
224
+
plcbundle-go op find bafyreig3... | awk '{print $3, $5}' | xargs plcbundle-go op get`,
225
225
226
226
Args: cobra.ExactArgs(1),
227
227
+1
-1
cmd/plcbundle/commands/progress_helper.go
+1
-1
cmd/plcbundle/commands/progress_helper.go
+1
-1
cmd/plcbundle/commands/query.go
+1
-1
cmd/plcbundle/commands/query.go
···
15
15
"github.com/goccy/go-json"
16
16
"github.com/jmespath-community/go-jmespath" // Correct import
17
17
"github.com/spf13/cobra"
18
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/ui"
18
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/ui"
19
19
)
20
20
21
21
func NewQueryCommand() *cobra.Command {
+9
-9
cmd/plcbundle/commands/rollback.go
+9
-9
cmd/plcbundle/commands/rollback.go
···
8
8
"strings"
9
9
10
10
"github.com/spf13/cobra"
11
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/ui"
12
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
11
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/ui"
12
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
13
13
)
14
14
15
15
func NewRollbackCommand() *cobra.Command {
···
46
46
7. Optionally rebuilds DID index`,
47
47
48
48
Example: ` # Rollback TO bundle 100 (keeps 1-100, removes 101+)
49
-
plcbundle rollback --to 100
49
+
plcbundle-go rollback --to 100
50
50
51
51
# Remove last 5 bundles
52
-
plcbundle rollback --last 5
52
+
plcbundle-go rollback --last 5
53
53
54
54
# Rollback without confirmation
55
-
plcbundle rollback --to 50 --force
55
+
plcbundle-go rollback --to 50 --force
56
56
57
57
# Rollback and rebuild DID index
58
-
plcbundle rollback --to 100 --rebuild-did-index
58
+
plcbundle-go rollback --to 100 --rebuild-did-index
59
59
60
60
# Rollback but keep bundle files (index-only)
61
-
plcbundle rollback --to 100 --keep-files`,
61
+
plcbundle-go rollback --to 100 --keep-files`,
62
62
63
63
RunE: func(cmd *cobra.Command, args []string) error {
64
64
verbose, _ := cmd.Root().PersistentFlags().GetBool("verbose")
···
464
464
fmt.Printf(" Index has bundle %06d, but repository now at %06d\n",
465
465
config.LastBundle, plan.targetBundle)
466
466
}
467
-
fmt.Printf(" Run: plcbundle index build\n")
467
+
fmt.Printf(" Run: plcbundle-go index build\n")
468
468
}
469
469
470
470
return nil
···
524
524
if !opts.rebuildDIDIndex && plan.hasDIDIndex {
525
525
fmt.Printf("๐ก Next Steps\n")
526
526
fmt.Printf(" DID index is out of date. Rebuild with:\n")
527
-
fmt.Printf(" plcbundle index build\n\n")
527
+
fmt.Printf(" plcbundle-go index build\n\n")
528
528
}
529
529
}
+14
-14
cmd/plcbundle/commands/server.go
+14
-14
cmd/plcbundle/commands/server.go
···
9
9
"time"
10
10
11
11
"github.com/spf13/cobra"
12
-
"tangled.org/atscan.net/plcbundle/bundle"
13
-
internalsync "tangled.org/atscan.net/plcbundle/internal/sync"
14
-
"tangled.org/atscan.net/plcbundle/server"
12
+
"tangled.org/atscan.net/plcbundle-go/bundle"
13
+
internalsync "tangled.org/atscan.net/plcbundle-go/internal/sync"
14
+
"tangled.org/atscan.net/plcbundle-go/server"
15
15
)
16
16
17
17
func NewServerCommand() *cobra.Command {
···
43
43
- Live mempool (in sync mode)
44
44
45
45
Sync mode (--sync) runs as a daemon, continuously fetching new bundles.
46
-
For one-time sync, use 'plcbundle sync' command instead.`,
46
+
For one-time sync, use 'plcbundle-go sync' command instead.`,
47
47
48
48
Example: ` # Basic server (read-only, current directory)
49
-
plcbundle server
49
+
plcbundle-go server
50
50
51
51
# Server with specific directory
52
-
plcbundle server --dir ./my-bundles
52
+
plcbundle-go server --dir ./my-bundles
53
53
54
54
# Live syncing server (daemon mode)
55
-
plcbundle server --sync
56
-
plcbundle server -s
55
+
plcbundle-go server --sync
56
+
plcbundle-go server -s
57
57
58
58
# Using alias
59
-
plcbundle serve -s
59
+
plcbundle-go serve -s
60
60
61
61
# Custom port and host
62
-
plcbundle server --port 3000 --host 0.0.0.0
62
+
plcbundle-go server --port 3000 --host 0.0.0.0
63
63
64
64
# Full featured server
65
-
plcbundle server -s --websocket --resolver
65
+
plcbundle-go server -s --websocket --resolver
66
66
67
67
# Fast sync interval
68
-
plcbundle server -s --interval 30s
68
+
plcbundle-go server -s --interval 30s
69
69
70
70
# Sync with limit (stop after 1000 bundles)
71
-
plcbundle server -s --max-bundles 1000
71
+
plcbundle-go server -s --max-bundles 1000
72
72
73
73
# Public server with all features
74
-
plcbundle serve -s --websocket --resolver --host 0.0.0.0 --port 80`,
74
+
plcbundle-go serve -s --websocket --resolver --host 0.0.0.0 --port 80`,
75
75
76
76
RunE: func(cmd *cobra.Command, args []string) error {
77
77
verbose, _ := cmd.Root().PersistentFlags().GetBool("verbose")
+6
-6
cmd/plcbundle/commands/status.go
+6
-6
cmd/plcbundle/commands/status.go
···
6
6
"time"
7
7
8
8
"github.com/spf13/cobra"
9
-
"tangled.org/atscan.net/plcbundle/bundle"
10
-
"tangled.org/atscan.net/plcbundle/internal/types"
9
+
"tangled.org/atscan.net/plcbundle-go/bundle"
10
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
11
11
)
12
12
13
13
func NewStatusCommand() *cobra.Command {
···
21
21
storage, timeline, mempool, and DID index status.`,
22
22
23
23
Example: ` # Show status
24
-
plcbundle status
24
+
plcbundle-go status
25
25
26
26
# Using alias
27
-
plcbundle info`,
27
+
plcbundle-go info`,
28
28
29
29
RunE: func(cmd *cobra.Command, args []string) error {
30
30
mgr, dir, err := getManager(&ManagerOptions{Cmd: cmd})
···
61
61
if bundleCount == 0 {
62
62
fmt.Printf("โ ๏ธ Empty repository (no bundles)\n\n")
63
63
fmt.Printf("Get started:\n")
64
-
fmt.Printf(" plcbundle clone <url> Clone from remote\n")
65
-
fmt.Printf(" plcbundle sync Fetch from PLC directory\n\n")
64
+
fmt.Printf(" plcbundle-go clone <url> Clone from remote\n")
65
+
fmt.Printf(" plcbundle-go sync Fetch from PLC directory\n\n")
66
66
return nil
67
67
}
68
68
+9
-9
cmd/plcbundle/commands/sync.go
+9
-9
cmd/plcbundle/commands/sync.go
···
9
9
"time"
10
10
11
11
"github.com/spf13/cobra"
12
-
"tangled.org/atscan.net/plcbundle/bundle"
13
-
internalsync "tangled.org/atscan.net/plcbundle/internal/sync"
12
+
"tangled.org/atscan.net/plcbundle-go/bundle"
13
+
internalsync "tangled.org/atscan.net/plcbundle-go/internal/sync"
14
14
)
15
15
16
16
func NewSyncCommand() *cobra.Command {
···
34
34
that continuously syncs at regular intervals.`,
35
35
36
36
Example: ` # Fetch new bundles once
37
-
plcbundle sync
37
+
plcbundle-go sync
38
38
39
39
# Fetch from specific directory
40
-
plcbundle sync --dir ./my-bundles
40
+
plcbundle-go sync --dir ./my-bundles
41
41
42
42
# Run continuously (daemon mode)
43
-
plcbundle sync --continuous
43
+
plcbundle-go sync --continuous
44
44
45
45
# Custom sync interval
46
-
plcbundle sync --continuous --interval 30s
46
+
plcbundle-go sync --continuous --interval 30s
47
47
48
48
# Fetch maximum 10 bundles then stop
49
-
plcbundle sync --max-bundles 10
49
+
plcbundle-go sync --max-bundles 10
50
50
51
51
# Continuous with limit
52
-
plcbundle sync --continuous --max-bundles 100 --interval 1m
52
+
plcbundle-go sync --continuous --max-bundles 100 --interval 1m
53
53
54
54
# Verbose output
55
-
plcbundle sync --continuous -v`,
55
+
plcbundle-go sync --continuous -v`,
56
56
57
57
RunE: func(cmd *cobra.Command, args []string) error {
58
58
verbose, _ := cmd.Root().PersistentFlags().GetBool("verbose")
+8
-8
cmd/plcbundle/commands/verify.go
+8
-8
cmd/plcbundle/commands/verify.go
···
7
7
"time"
8
8
9
9
"github.com/spf13/cobra"
10
-
"tangled.org/atscan.net/plcbundle/bundle"
11
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/ui"
10
+
"tangled.org/atscan.net/plcbundle-go/bundle"
11
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/ui"
12
12
)
13
13
14
14
func NewVerifyCommand() *cobra.Command {
···
37
37
โข Chain hash calculations are valid`,
38
38
39
39
Example: ` # Verify entire chain
40
-
plcbundle verify
41
-
plcbundle verify --chain
40
+
plcbundle-go verify
41
+
plcbundle-go verify --chain
42
42
43
43
# Verify specific bundle
44
-
plcbundle verify --bundle 42
44
+
plcbundle-go verify --bundle 42
45
45
46
46
# Verify range of bundles
47
-
plcbundle verify --range 1-100
47
+
plcbundle-go verify --range 1-100
48
48
49
49
# Verbose output
50
-
plcbundle verify --chain -v
50
+
plcbundle-go verify --chain -v
51
51
52
52
# Parallel verification (faster for ranges)
53
-
plcbundle verify --range 1-1000 --parallel --workers 8`,
53
+
plcbundle-go verify --range 1-1000 --parallel --workers 8`,
54
54
55
55
RunE: func(cmd *cobra.Command, args []string) error {
56
56
verbose, _ := cmd.Root().PersistentFlags().GetBool("verbose")
+15
-15
cmd/plcbundle/main.go
+15
-15
cmd/plcbundle/main.go
···
5
5
"os"
6
6
7
7
"github.com/spf13/cobra"
8
-
"tangled.org/atscan.net/plcbundle/cmd/plcbundle/commands"
8
+
"tangled.org/atscan.net/plcbundle-go/cmd/plcbundle/commands"
9
9
)
10
10
11
11
func main() {
···
20
20
21
21
func newRootCommand() *cobra.Command {
22
22
cmd := &cobra.Command{
23
-
Use: "plcbundle",
23
+
Use: "plcbundle-go",
24
24
Short: "DID PLC Bundle Management Tool",
25
-
Long: `plcbundle - DID PLC Bundle Management Tool
25
+
Long: `plcbundle-go - DID PLC Bundle Management Tool
26
26
27
27
Tool for archiving AT Protocol's DID PLC Directory operations
28
28
into immutable, cryptographically-chained bundles of 10,000
···
89
89
Use: "version",
90
90
Short: "Show version information",
91
91
Run: func(cmd *cobra.Command, args []string) {
92
-
cmd.Printf("plcbundle version %s\n", GetVersion())
92
+
cmd.Printf("plcbundle-go version %s\n", GetVersion())
93
93
cmd.Printf(" commit: %s\n", getGitCommit())
94
94
cmd.Printf(" built: %s\n", getBuildDate())
95
95
},
···
105
105
To load completions:
106
106
107
107
Bash:
108
-
$ source <(plcbundle completion bash)
108
+
$ source <(plcbundle-go completion bash)
109
109
110
110
# To load automatically:
111
-
$ plcbundle completion bash > /etc/bash_completion.d/plcbundle
111
+
$ plcbundle-go completion bash > /etc/bash_completion.d/plcbundle-go
112
112
113
113
Zsh:
114
-
$ plcbundle completion zsh > ~/.zsh/completion/_plcbundle
114
+
$ plcbundle-go completion zsh > ~/.zsh/completion/_plcbundle-go
115
115
116
116
# Add to ~/.zshrc:
117
117
fpath=(~/.zsh/completion $fpath)
118
118
119
119
Fish:
120
-
$ plcbundle completion fish > ~/.config/fish/completions/plcbundle.fish`,
120
+
$ plcbundle-go completion fish > ~/.config/fish/completions/plcbundle-go.fish`,
121
121
122
122
Args: cobra.ExactArgs(1),
123
123
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
···
140
140
}
141
141
142
142
func printRootHelp() {
143
-
fmt.Print(`plcbundle ` + GetVersion() + ` - DID PLC Bundle Management
143
+
fmt.Print(`plcbundle-go ` + GetVersion() + ` - DID PLC Bundle Management
144
144
145
-
Usage: plcbundle <command> [options]
145
+
Usage: plcbundle-go <command> [options]
146
146
147
147
Main Commands:
148
148
sync Fetch new bundles from PLC
···
160
160
Tools: watch, heal, clean, mempool, detector
161
161
162
162
Getting Started:
163
-
plcbundle clone https://plc.example.com
164
-
plcbundle sync
165
-
plcbundle status
163
+
plcbundle-go clone https://plc.example.com
164
+
plcbundle-go sync
165
+
plcbundle-go status
166
166
167
-
Run 'plcbundle help' for full documentation
168
-
Run 'plcbundle <command> --help' for command help
167
+
Run 'plcbundle-go help' for full documentation
168
+
Run 'plcbundle-go <command> --help' for command help
169
169
`)
170
170
}
+1
-1
detector/builtin.go
+1
-1
detector/builtin.go
+1
-1
detector/detector.go
+1
-1
detector/detector.go
+2
-2
detector/runner.go
+2
-2
detector/runner.go
···
7
7
"sync"
8
8
"time"
9
9
10
-
"tangled.org/atscan.net/plcbundle/bundle"
11
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
10
+
"tangled.org/atscan.net/plcbundle-go/bundle"
11
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
12
12
)
13
13
14
14
// Runner executes detectors against operations
+1
-1
detector/script.go
+1
-1
detector/script.go
+2
-5
go.mod
+2
-5
go.mod
···
1
-
module tangled.org/atscan.net/plcbundle
1
+
module tangled.org/atscan.net/plcbundle-go
2
2
3
-
go 1.25.3
3
+
go 1.25
4
4
5
5
require (
6
6
github.com/goccy/go-json v0.10.5
···
10
10
github.com/valyala/gozstd v1.23.2
11
11
golang.org/x/sys v0.38.0
12
12
golang.org/x/term v0.36.0
13
-
tangled.org/atscan.net/plcbundle-rs/bindings/go v0.0.0
14
13
)
15
-
16
-
replace tangled.org/atscan.net/plcbundle-rs/bindings/go => ../plcbundle-rs/bindings/go
17
14
18
15
require (
19
16
github.com/inconshreveable/mousetrap v1.1.0 // indirect
+2
-2
internal/bundleindex/index_test.go
+2
-2
internal/bundleindex/index_test.go
···
8
8
"testing"
9
9
"time"
10
10
11
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
12
-
"tangled.org/atscan.net/plcbundle/internal/types"
11
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
12
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
13
13
)
14
14
15
15
type testLogger struct {
+1
-1
internal/didindex/bundle.go
+1
-1
internal/didindex/bundle.go
+1
-1
internal/didindex/lookup.go
+1
-1
internal/didindex/lookup.go
+1
-1
internal/didindex/manager.go
+1
-1
internal/didindex/manager.go
+1
-1
internal/didindex/manager_test.go
+1
-1
internal/didindex/manager_test.go
+1
-1
internal/didindex/types.go
+1
-1
internal/didindex/types.go
+2
-2
internal/mempool/mempool.go
+2
-2
internal/mempool/mempool.go
···
10
10
"time"
11
11
12
12
"github.com/goccy/go-json"
13
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
14
-
"tangled.org/atscan.net/plcbundle/internal/types"
13
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
14
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
15
15
)
16
16
17
17
const MEMPOOL_FILE_PREFIX = "plc_mempool_"
+3
-3
internal/mempool/mempool_test.go
+3
-3
internal/mempool/mempool_test.go
···
8
8
"testing"
9
9
"time"
10
10
11
-
"tangled.org/atscan.net/plcbundle/internal/mempool"
12
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
13
-
"tangled.org/atscan.net/plcbundle/internal/types"
11
+
"tangled.org/atscan.net/plcbundle-go/internal/mempool"
12
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
13
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
14
14
)
15
15
16
16
type testLogger struct {
+2
-2
internal/plcclient/plc_test.go
+2
-2
internal/plcclient/plc_test.go
···
8
8
"testing"
9
9
"time"
10
10
11
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
12
-
"tangled.org/atscan.net/plcbundle/internal/storage"
11
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
12
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
13
13
)
14
14
15
15
// TestPLCOperation tests operation parsing and methods
+1
-1
internal/storage/storage.go
+1
-1
internal/storage/storage.go
+2
-2
internal/storage/storage_test.go
+2
-2
internal/storage/storage_test.go
···
10
10
"testing"
11
11
"time"
12
12
13
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
14
-
"tangled.org/atscan.net/plcbundle/internal/storage"
13
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
14
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
15
15
)
16
16
17
17
type testLogger struct {
+2
-2
internal/sync/bundler.go
+2
-2
internal/sync/bundler.go
···
3
3
import (
4
4
"time"
5
5
6
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
7
-
"tangled.org/atscan.net/plcbundle/internal/storage"
6
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
7
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
8
8
)
9
9
10
10
// CreateBundle creates a bundle structure from operations
+3
-3
internal/sync/cloner.go
+3
-3
internal/sync/cloner.go
···
12
12
"time"
13
13
14
14
"github.com/goccy/go-json"
15
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
16
-
"tangled.org/atscan.net/plcbundle/internal/storage"
17
-
"tangled.org/atscan.net/plcbundle/internal/types"
15
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
16
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
17
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
18
18
)
19
19
20
20
// Cloner handles cloning bundles from remote endpoints
+3
-3
internal/sync/fetcher.go
+3
-3
internal/sync/fetcher.go
···
5
5
"fmt"
6
6
"time"
7
7
8
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
9
-
"tangled.org/atscan.net/plcbundle/internal/storage"
10
-
"tangled.org/atscan.net/plcbundle/internal/types"
8
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
9
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
10
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
11
11
)
12
12
13
13
// Fetcher handles fetching operations from PLC directory
+4
-4
internal/sync/sync_test.go
+4
-4
internal/sync/sync_test.go
···
11
11
"time"
12
12
13
13
"github.com/goccy/go-json"
14
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
15
-
"tangled.org/atscan.net/plcbundle/internal/storage"
16
-
internalsync "tangled.org/atscan.net/plcbundle/internal/sync"
17
-
"tangled.org/atscan.net/plcbundle/internal/types"
14
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
15
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
16
+
internalsync "tangled.org/atscan.net/plcbundle-go/internal/sync"
17
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
18
18
)
19
19
20
20
type testLogger struct {
+1
-1
internal/sync/syncer.go
+1
-1
internal/sync/syncer.go
+1
-1
internal/types/types_test.go
+1
-1
internal/types/types_test.go
+2
-2
options.go
+2
-2
options.go
+2
-2
server/handlers.go
+2
-2
server/handlers.go
···
11
11
"time"
12
12
13
13
"github.com/goccy/go-json"
14
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
15
-
"tangled.org/atscan.net/plcbundle/internal/types"
14
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
15
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
16
16
)
17
17
18
18
func (s *Server) handleRoot() http.HandlerFunc {
+1
-1
server/helpers.go
+1
-1
server/helpers.go
+1
-1
server/server.go
+1
-1
server/server.go
+5
-5
server/server_test.go
+5
-5
server/server_test.go
···
15
15
"time"
16
16
17
17
"github.com/gorilla/websocket"
18
-
"tangled.org/atscan.net/plcbundle/bundle"
19
-
"tangled.org/atscan.net/plcbundle/internal/bundleindex"
20
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
21
-
"tangled.org/atscan.net/plcbundle/internal/storage"
22
-
"tangled.org/atscan.net/plcbundle/server"
18
+
"tangled.org/atscan.net/plcbundle-go/bundle"
19
+
"tangled.org/atscan.net/plcbundle-go/internal/bundleindex"
20
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
21
+
"tangled.org/atscan.net/plcbundle-go/internal/storage"
22
+
"tangled.org/atscan.net/plcbundle-go/server"
23
23
)
24
24
25
25
type testLogger struct {
+1
-1
server/types.go
+1
-1
server/types.go
+1
-1
server/types_test.go
+1
-1
server/types_test.go
+2
-2
server/websocket.go
+2
-2
server/websocket.go
···
11
11
12
12
"github.com/goccy/go-json"
13
13
"github.com/gorilla/websocket"
14
-
"tangled.org/atscan.net/plcbundle/internal/plcclient"
15
-
"tangled.org/atscan.net/plcbundle/internal/types"
14
+
"tangled.org/atscan.net/plcbundle-go/internal/plcclient"
15
+
"tangled.org/atscan.net/plcbundle-go/internal/types"
16
16
)
17
17
18
18
var upgrader = websocket.Upgrader{