@awiki/cli 0.0.1-beta.2
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/.github/workflows/release.yml +44 -0
- package/.goreleaser.yml +44 -0
- package/AGENTS.md +60 -0
- package/CLAUDE.md +192 -0
- package/README.md +2 -0
- package/docs/architecture/awiki-command-v2.md +955 -0
- package/docs/architecture/awiki-skill-architecture.md +475 -0
- package/docs/architecture/awiki-v2-architecture.md +1063 -0
- package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/cli-init.md +1008 -0
- package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/output-format.md +407 -0
- package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/overall-init.md +741 -0
- package/docs/harness/review-spec.md +474 -0
- package/docs/installation.md +372 -0
- package/docs/plan/awiki-v2-implementation-plan.md +903 -0
- package/docs/plan/phase-0/adr-index.md +56 -0
- package/docs/plan/phase-0/audit-findings.md +251 -0
- package/docs/plan/phase-0/capability-mapping.md +108 -0
- package/docs/plan/phase-0/implementation-constraints.md +363 -0
- package/docs/publish.md +169 -0
- package/go.mod +29 -0
- package/go.sum +73 -0
- package/internal/anpsdk/registry.go +63 -0
- package/internal/authsdk/session.go +351 -0
- package/internal/buildinfo/buildinfo.go +34 -0
- package/internal/cli/app.go +136 -0
- package/internal/cli/app_test.go +88 -0
- package/internal/cli/debug.go +104 -0
- package/internal/cli/group.go +263 -0
- package/internal/cli/id.go +473 -0
- package/internal/cli/init.go +134 -0
- package/internal/cli/msg.go +228 -0
- package/internal/cli/page.go +267 -0
- package/internal/cli/root.go +499 -0
- package/internal/cli/runtime.go +232 -0
- package/internal/cli/upgrade.go +60 -0
- package/internal/cmdmeta/catalog.go +203 -0
- package/internal/cmdmeta/catalog_test.go +21 -0
- package/internal/config/config.go +399 -0
- package/internal/config/config_test.go +104 -0
- package/internal/config/write.go +37 -0
- package/internal/content/service.go +314 -0
- package/internal/content/service_test.go +165 -0
- package/internal/content/types.go +44 -0
- package/internal/docs/topics.go +110 -0
- package/internal/doctor/doctor.go +306 -0
- package/internal/identity/client.go +267 -0
- package/internal/identity/did.go +85 -0
- package/internal/identity/did_test.go +50 -0
- package/internal/identity/layout.go +206 -0
- package/internal/identity/legacy.go +378 -0
- package/internal/identity/public.go +70 -0
- package/internal/identity/public_test.go +73 -0
- package/internal/identity/readiness.go +74 -0
- package/internal/identity/service.go +826 -0
- package/internal/identity/store.go +385 -0
- package/internal/identity/store_test.go +180 -0
- package/internal/identity/types.go +204 -0
- package/internal/message/auth.go +167 -0
- package/internal/message/group_service.go +838 -0
- package/internal/message/group_wire.go +350 -0
- package/internal/message/group_wire_test.go +67 -0
- package/internal/message/helpers.go +61 -0
- package/internal/message/http_client.go +334 -0
- package/internal/message/proof.go +156 -0
- package/internal/message/proof_test.go +61 -0
- package/internal/message/service.go +696 -0
- package/internal/message/service_test.go +97 -0
- package/internal/message/types.go +155 -0
- package/internal/message/wire.go +100 -0
- package/internal/message/wire_test.go +49 -0
- package/internal/message/ws_proxy_client.go +151 -0
- package/internal/output/output.go +350 -0
- package/internal/output/output_test.go +48 -0
- package/internal/runtime/config.go +117 -0
- package/internal/runtime/config_test.go +46 -0
- package/internal/runtime/listener/files.go +65 -0
- package/internal/runtime/listener/manager.go +142 -0
- package/internal/runtime/listener/server.go +983 -0
- package/internal/runtime/listener/server_test.go +319 -0
- package/internal/runtime/listener/sysproc_unix.go +17 -0
- package/internal/runtime/listener/sysproc_windows.go +13 -0
- package/internal/runtime/listener/types.go +21 -0
- package/internal/runtime/listener/wsclient.go +299 -0
- package/internal/runtime/listener/wsclient_test.go +41 -0
- package/internal/store/dao.go +632 -0
- package/internal/store/dao_test.go +87 -0
- package/internal/store/helpers.go +197 -0
- package/internal/store/import.go +499 -0
- package/internal/store/import_test.go +103 -0
- package/internal/store/open.go +71 -0
- package/internal/store/query.go +151 -0
- package/internal/store/schema.go +277 -0
- package/internal/store/schema_test.go +56 -0
- package/internal/store/types.go +177 -0
- package/internal/update/update.go +368 -0
- package/package.json +17 -0
- package/scripts/install.js +171 -0
- package/scripts/release/release-prerelease.sh +86 -0
- package/scripts/release/tag-release.sh +66 -0
- package/scripts/release/withdraw-release.sh +78 -0
- package/scripts/run.js +69 -0
- package/skills/README.md +32 -0
- package/skills/awiki-bundle/SKILL.md +76 -0
- package/skills/awiki-debug/SKILL.md +80 -0
- package/skills/awiki-group/SKILL.md +111 -0
- package/skills/awiki-id/SKILL.md +123 -0
- package/skills/awiki-msg/SKILL.md +131 -0
- package/skills/awiki-page/SKILL.md +93 -0
- package/skills/awiki-people/SKILL.md +66 -0
- package/skills/awiki-runtime/SKILL.md +137 -0
- package/skills/awiki-shared/SKILL.md +124 -0
- package/skills/awiki-workflow-discovery/SKILL.md +93 -0
- package/skills/awiki-workflow-onboarding/SKILL.md +119 -0
- package/skills/manifests/skills.yaml +260 -0
- package/skills/templates/bundle-skill-template.md +42 -0
- package/skills/templates/debug-skill-template.md +44 -0
- package/skills/templates/domain-skill-template.md +56 -0
- package/skills/templates/shared-skill-template.md +46 -0
- package/skills/templates/workflow-skill-template.md +46 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
package store
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
func TestStoreMessageAndThreadView(t *testing.T) {
|
|
9
|
+
t.Parallel()
|
|
10
|
+
|
|
11
|
+
db := openTestDB(t)
|
|
12
|
+
ctx := context.Background()
|
|
13
|
+
if err := EnsureSchema(ctx, db); err != nil {
|
|
14
|
+
t.Fatalf("EnsureSchema() error = %v", err)
|
|
15
|
+
}
|
|
16
|
+
if err := StoreMessage(ctx, db, MessageRecord{
|
|
17
|
+
MsgID: "msg-1",
|
|
18
|
+
OwnerDID: "did:wba:awiki.ai:user:a",
|
|
19
|
+
ThreadID: MakeThreadID("did:wba:awiki.ai:user:a", "did:wba:awiki.ai:user:b", ""),
|
|
20
|
+
Direction: 0,
|
|
21
|
+
SenderDID: "did:wba:awiki.ai:user:b",
|
|
22
|
+
ReceiverDID: "did:wba:awiki.ai:user:a",
|
|
23
|
+
ContentType: "text",
|
|
24
|
+
Content: "hello",
|
|
25
|
+
IsRead: false,
|
|
26
|
+
CredentialName: "default",
|
|
27
|
+
}); err != nil {
|
|
28
|
+
t.Fatalf("StoreMessage() error = %v", err)
|
|
29
|
+
}
|
|
30
|
+
got, err := GetMessageByID(ctx, db, "msg-1", "did:wba:awiki.ai:user:a", "")
|
|
31
|
+
if err != nil {
|
|
32
|
+
t.Fatalf("GetMessageByID() error = %v", err)
|
|
33
|
+
}
|
|
34
|
+
if got["content"] != "hello" {
|
|
35
|
+
t.Fatalf("unexpected message content: %#v", got)
|
|
36
|
+
}
|
|
37
|
+
rows, err := ExecuteSQL(ctx, db, "SELECT thread_id, unread_count FROM threads")
|
|
38
|
+
if err != nil {
|
|
39
|
+
t.Fatalf("ExecuteSQL() error = %v", err)
|
|
40
|
+
}
|
|
41
|
+
if len(rows) != 1 {
|
|
42
|
+
t.Fatalf("unexpected threads rows: %#v", rows)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func TestRebindOwnerDIDAndClearE2EEData(t *testing.T) {
|
|
47
|
+
t.Parallel()
|
|
48
|
+
|
|
49
|
+
db := openTestDB(t)
|
|
50
|
+
ctx := context.Background()
|
|
51
|
+
if err := EnsureSchema(ctx, db); err != nil {
|
|
52
|
+
t.Fatalf("EnsureSchema() error = %v", err)
|
|
53
|
+
}
|
|
54
|
+
if _, err := QueueE2EEOutbox(ctx, db, E2EEOutboxRecord{
|
|
55
|
+
OutboxID: "out-1",
|
|
56
|
+
OwnerDID: "did:old",
|
|
57
|
+
PeerDID: "did:peer",
|
|
58
|
+
Plaintext: "secret",
|
|
59
|
+
LocalStatus: "queued",
|
|
60
|
+
CredentialName: "default",
|
|
61
|
+
}); err != nil {
|
|
62
|
+
t.Fatalf("QueueE2EEOutbox() error = %v", err)
|
|
63
|
+
}
|
|
64
|
+
if _, err := db.ExecContext(ctx, `
|
|
65
|
+
INSERT INTO e2ee_sessions
|
|
66
|
+
(owner_did, peer_did, session_id, is_initiator, send_chain_key, recv_chain_key, send_seq, recv_seq, expires_at, created_at, active_at, peer_confirmed, credential_name, updated_at)
|
|
67
|
+
VALUES ('did:old', 'did:peer', 'sess-1', 1, 'send', 'recv', 0, 0, NULL, '2026-01-01T00:00:00Z', NULL, 0, 'default', '2026-01-01T00:00:00Z')`); err != nil {
|
|
68
|
+
t.Fatalf("insert e2ee session error = %v", err)
|
|
69
|
+
}
|
|
70
|
+
if err := UpsertContact(ctx, db, ContactRecord{OwnerDID: "did:old", DID: "did:peer", Name: "Peer"}); err != nil {
|
|
71
|
+
t.Fatalf("UpsertContact() error = %v", err)
|
|
72
|
+
}
|
|
73
|
+
result, err := RebindOwnerDID(ctx, db, "did:old", "did:new")
|
|
74
|
+
if err != nil {
|
|
75
|
+
t.Fatalf("RebindOwnerDID() error = %v", err)
|
|
76
|
+
}
|
|
77
|
+
if result["contacts"] != 1 {
|
|
78
|
+
t.Fatalf("unexpected rebind counts: %#v", result)
|
|
79
|
+
}
|
|
80
|
+
cleared, err := ClearOwnerE2EEData(ctx, db, "did:old")
|
|
81
|
+
if err != nil {
|
|
82
|
+
t.Fatalf("ClearOwnerE2EEData() error = %v", err)
|
|
83
|
+
}
|
|
84
|
+
if cleared["e2ee_outbox"] != 1 || cleared["e2ee_sessions"] != 1 {
|
|
85
|
+
t.Fatalf("unexpected clear result: %#v", cleared)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
package store
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"database/sql"
|
|
6
|
+
"encoding/json"
|
|
7
|
+
"fmt"
|
|
8
|
+
"regexp"
|
|
9
|
+
"sort"
|
|
10
|
+
"strings"
|
|
11
|
+
"time"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
var (
|
|
15
|
+
forbiddenPatterns = []*regexp.Regexp{
|
|
16
|
+
regexp.MustCompile(`\bDROP\b`),
|
|
17
|
+
regexp.MustCompile(`\bTRUNCATE\b`),
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
func nowUTC() string {
|
|
22
|
+
return time.Now().UTC().Format(time.RFC3339)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func MakeThreadID(myDID string, peerDID string, groupID string) string {
|
|
26
|
+
if strings.TrimSpace(groupID) != "" {
|
|
27
|
+
return fmt.Sprintf("group:%s", strings.TrimSpace(groupID))
|
|
28
|
+
}
|
|
29
|
+
if strings.TrimSpace(peerDID) != "" {
|
|
30
|
+
pair := []string{strings.TrimSpace(myDID), strings.TrimSpace(peerDID)}
|
|
31
|
+
sort.Strings(pair)
|
|
32
|
+
return fmt.Sprintf("dm:%s:%s", pair[0], pair[1])
|
|
33
|
+
}
|
|
34
|
+
return fmt.Sprintf("dm:%s:unknown", strings.TrimSpace(myDID))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func normalizeOwnerDID(value string) string {
|
|
38
|
+
return strings.TrimSpace(value)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func normalizeCredentialName(value string) string {
|
|
42
|
+
return strings.TrimSpace(value)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func normalizeOptionalString(value string) any {
|
|
46
|
+
value = strings.TrimSpace(value)
|
|
47
|
+
if value == "" {
|
|
48
|
+
return nil
|
|
49
|
+
}
|
|
50
|
+
return value
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func normalizeOptionalBool(value *bool) any {
|
|
54
|
+
if value == nil {
|
|
55
|
+
return nil
|
|
56
|
+
}
|
|
57
|
+
if *value {
|
|
58
|
+
return 1
|
|
59
|
+
}
|
|
60
|
+
return 0
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func normalizeOptionalInt64(value *int64) any {
|
|
64
|
+
if value == nil {
|
|
65
|
+
return nil
|
|
66
|
+
}
|
|
67
|
+
return *value
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
func normalizeOptionalFloat64(value *float64) any {
|
|
71
|
+
if value == nil {
|
|
72
|
+
return nil
|
|
73
|
+
}
|
|
74
|
+
return *value
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func defaultInt64Ptr(value *int64, fallback *int64) *int64 {
|
|
78
|
+
if value != nil {
|
|
79
|
+
return value
|
|
80
|
+
}
|
|
81
|
+
return fallback
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
func normalizeMetadata(value string) any {
|
|
85
|
+
value = strings.TrimSpace(value)
|
|
86
|
+
if value == "" {
|
|
87
|
+
return nil
|
|
88
|
+
}
|
|
89
|
+
return value
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
func metadataFromAny(value any) string {
|
|
93
|
+
if value == nil {
|
|
94
|
+
return ""
|
|
95
|
+
}
|
|
96
|
+
switch typed := value.(type) {
|
|
97
|
+
case string:
|
|
98
|
+
return typed
|
|
99
|
+
default:
|
|
100
|
+
raw, err := json.Marshal(typed)
|
|
101
|
+
if err != nil {
|
|
102
|
+
return ""
|
|
103
|
+
}
|
|
104
|
+
return string(raw)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
func queryMaps(ctx context.Context, db *sql.DB, query string, args ...any) ([]map[string]any, error) {
|
|
109
|
+
rows, err := db.QueryContext(ctx, query, args...)
|
|
110
|
+
if err != nil {
|
|
111
|
+
return nil, err
|
|
112
|
+
}
|
|
113
|
+
defer rows.Close()
|
|
114
|
+
columns, err := rows.Columns()
|
|
115
|
+
if err != nil {
|
|
116
|
+
return nil, err
|
|
117
|
+
}
|
|
118
|
+
results := make([]map[string]any, 0)
|
|
119
|
+
for rows.Next() {
|
|
120
|
+
values := make([]any, len(columns))
|
|
121
|
+
pointers := make([]any, len(columns))
|
|
122
|
+
for index := range values {
|
|
123
|
+
pointers[index] = &values[index]
|
|
124
|
+
}
|
|
125
|
+
if err := rows.Scan(pointers...); err != nil {
|
|
126
|
+
return nil, err
|
|
127
|
+
}
|
|
128
|
+
item := make(map[string]any, len(columns))
|
|
129
|
+
for index, column := range columns {
|
|
130
|
+
item[column] = convertSQLiteValue(values[index])
|
|
131
|
+
}
|
|
132
|
+
results = append(results, item)
|
|
133
|
+
}
|
|
134
|
+
return results, rows.Err()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
func queryOneMap(ctx context.Context, db *sql.DB, query string, args ...any) (map[string]any, error) {
|
|
138
|
+
rows, err := queryMaps(ctx, db, query, args...)
|
|
139
|
+
if err != nil {
|
|
140
|
+
return nil, err
|
|
141
|
+
}
|
|
142
|
+
if len(rows) == 0 {
|
|
143
|
+
return nil, sql.ErrNoRows
|
|
144
|
+
}
|
|
145
|
+
return rows[0], nil
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
func convertSQLiteValue(value any) any {
|
|
149
|
+
switch typed := value.(type) {
|
|
150
|
+
case []byte:
|
|
151
|
+
return string(typed)
|
|
152
|
+
default:
|
|
153
|
+
return typed
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
func tableExists(ctx context.Context, db *sql.DB, tableName string) (bool, error) {
|
|
158
|
+
var exists int
|
|
159
|
+
row := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = ?", tableName)
|
|
160
|
+
if err := row.Scan(&exists); err != nil {
|
|
161
|
+
return false, err
|
|
162
|
+
}
|
|
163
|
+
return exists > 0, nil
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
func viewExists(ctx context.Context, db *sql.DB, viewName string) (bool, error) {
|
|
167
|
+
var exists int
|
|
168
|
+
row := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM sqlite_master WHERE type = 'view' AND name = ?", viewName)
|
|
169
|
+
if err := row.Scan(&exists); err != nil {
|
|
170
|
+
return false, err
|
|
171
|
+
}
|
|
172
|
+
return exists > 0, nil
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
func columnNames(ctx context.Context, db *sql.DB, tableName string) (map[string]struct{}, error) {
|
|
176
|
+
rows, err := queryMaps(ctx, db, fmt.Sprintf("PRAGMA table_info(%s)", tableName))
|
|
177
|
+
if err != nil {
|
|
178
|
+
return nil, err
|
|
179
|
+
}
|
|
180
|
+
columns := make(map[string]struct{}, len(rows))
|
|
181
|
+
for _, row := range rows {
|
|
182
|
+
name, _ := row["name"].(string)
|
|
183
|
+
if name != "" {
|
|
184
|
+
columns[name] = struct{}{}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return columns, nil
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
func schemaVersion(ctx context.Context, db *sql.DB) (int, error) {
|
|
191
|
+
var version int
|
|
192
|
+
row := db.QueryRowContext(ctx, "PRAGMA user_version")
|
|
193
|
+
if err := row.Scan(&version); err != nil {
|
|
194
|
+
return 0, err
|
|
195
|
+
}
|
|
196
|
+
return version, nil
|
|
197
|
+
}
|