kira-wallet 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -4
- package/docs/CLI.md +25 -12
- package/docs/JOB_CONTRACT.md +13 -1
- package/docs/KIRA_DISCOVERY_ACCEPTANCE.md +95 -0
- package/docs/ONBOARDING_CHAT_CONTRACT.md +34 -1
- package/docs/RELEASE.md +32 -9
- package/kira_agent.py +14 -0
- package/kira_cli.py +3 -4
- package/kira_config.py +13 -0
- package/kira_jobs.py +14 -4
- package/kira_models.py +86 -0
- package/onchain.cjs +6 -1
- package/package.json +4 -2
- package/pipeline-onchain.cjs +19 -2
- package/sources/job-envelope-v1.schema.json +2 -1
- package/sources/job-request-v1.schema.json +43 -0
- package/viewer/model.py +10 -0
- package/viewer/onboarding.py +4 -2
- package/viewer/server.py +3 -1
- package/viewer/static/agent.js +65 -14
- package/viewer/static/app.js +30 -6
- package/viewer/static/index.html +30 -5
- package/viewer/static/jobs.js +110 -6
- package/viewer/static/report.js +4 -4
- package/viewer/static/style.css +2 -0
- package/viewer/static/watching.js +5 -1
- package/viewer/static/workspace-model.js +22 -1
- package/viewer/static/workspace.css +11 -3
- package/wallet.py +17 -5
package/README.md
CHANGED
|
@@ -43,11 +43,12 @@ For a viewer without wallet or research actions, use `kira start --read-only`.
|
|
|
43
43
|
Prefer an archive? [GitHub releases](https://github.com/realproject7/kira-wallet/releases/tag/v0.1.2)
|
|
44
44
|
include the same package and its checksum.
|
|
45
45
|
|
|
46
|
-
1. **
|
|
47
|
-
wallets whenever you need them.
|
|
48
|
-
2. **Set up discovery.** In **Workspace settings**, connect an indexer for broad
|
|
46
|
+
1. **Set up discovery.** In **Workspace settings**, connect an indexer for broad
|
|
49
47
|
ERC20 discovery. Public RPC alone has limited discovery; incomplete coverage
|
|
50
|
-
stays visible.
|
|
48
|
+
stays visible. An AI or browser wallet connection does not enable an indexer.
|
|
49
|
+
2. **Add a watching wallet.** Paste a public address and give it a name. Add more
|
|
50
|
+
wallets whenever you need them. Without discovery, the form explicitly
|
|
51
|
+
offers limited research of native and Mint Club assets.
|
|
51
52
|
3. **Connect your AI.** Install and sign in to the
|
|
52
53
|
[Codex CLI](https://developers.openai.com/codex/cli) or
|
|
53
54
|
[Claude Code](https://code.claude.com/docs/en/quickstart), then choose your
|
|
@@ -117,6 +118,12 @@ package. Use `--data-dir /absolute/private/directory` before a command to choose
|
|
|
117
118
|
another workspace. For connection, model or provider help, see the
|
|
118
119
|
[CLI guide](docs/CLI.md) and [viewer guide](viewer/README.md).
|
|
119
120
|
|
|
121
|
+
From 0.1.4, a partial wallet analysis explains disabled discovery, missing
|
|
122
|
+
credentials and network failures directly beside the holdings. After connecting
|
|
123
|
+
discovery, use **Refresh holdings** to create a new analysis. **Refresh prices**
|
|
124
|
+
does not discover missing tokens. Existing workspace provider settings and
|
|
125
|
+
published snapshots are preserved.
|
|
126
|
+
|
|
120
127
|
## Build and contribute
|
|
121
128
|
|
|
122
129
|
```sh
|
package/docs/CLI.md
CHANGED
|
@@ -10,8 +10,9 @@ npm install -g kira-wallet
|
|
|
10
10
|
kira setup
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
The
|
|
14
|
-
are available from the
|
|
13
|
+
The operator published npm version 0.1.4. Version 0.1.5 is a preparation candidate. GitHub v0.1.3 remains
|
|
14
|
+
a draft; the previous archive and checksum are available from the
|
|
15
|
+
[0.1.2 GitHub release](https://github.com/realproject7/kira-wallet/releases/tag/v0.1.2).
|
|
15
16
|
Registry publication remains an operator action. The code and original character assets use the MIT license.
|
|
16
17
|
|
|
17
18
|
## Lifecycle
|
|
@@ -33,7 +34,7 @@ read-only and control modes requires an explicit stop and restart. Starting
|
|
|
33
34
|
an already-running app in the same mode reuses its URL. The old `--controls`
|
|
34
35
|
option remains accepted for existing scripts but is no longer needed.
|
|
35
36
|
|
|
36
|
-
These startup defaults apply from 0.1.3. In the
|
|
37
|
+
These startup defaults apply from published 0.1.3. In the older 0.1.2 package, use
|
|
37
38
|
`kira setup` or `kira start --controls` for the full app.
|
|
38
39
|
|
|
39
40
|
The 0.1.2 GitHub release starts with a wallet checklist. Add a public EVM
|
|
@@ -41,17 +42,22 @@ address or use the browser wallet picker. Registration starts one explicit
|
|
|
41
42
|
research job; follow it in Activity and read the saved portfolio report.
|
|
42
43
|
No signature, seed phrase or private key is needed.
|
|
43
44
|
|
|
45
|
+
Published 0.1.4 explains limited discovery before wallet registration and beside
|
|
46
|
+
holdings. Missing coverage keeps the portfolio estimate partial. Existing snapshots require a holdings refresh after connecting
|
|
47
|
+
an indexer; a price refresh does not discover missing tokens.
|
|
48
|
+
|
|
44
49
|
Public RPC checks known assets and Mint Club. For broader ERC20 discovery,
|
|
45
|
-
open
|
|
46
|
-
|
|
50
|
+
open Data provider connection, select Alchemy and follow its local key guide.
|
|
51
|
+
The 0.1.5 candidate uses one save for Alchemy RPC and discovery; chain overrides
|
|
52
|
+
remain under Advanced. Never paste the key into the browser. `kira doctor`
|
|
47
53
|
checks whether the configured key is available. Configuration alone does not
|
|
48
54
|
prove complete coverage; inspect the recorded results and gaps.
|
|
49
55
|
|
|
50
56
|
Connecting Codex or Claude is optional. Use Connect your AI when ready, verify
|
|
51
57
|
a generic response and explicitly choose context permissions. Assistant answers
|
|
52
58
|
render a safe Markdown subset; raw HTML, images and links remain inert text.
|
|
53
|
-
|
|
54
|
-
0.1.0 package
|
|
59
|
+
The wallet-first setup is included in published npm 0.1.3. The historical
|
|
60
|
+
0.1.0 package uses the earlier account-first setup.
|
|
55
61
|
|
|
56
62
|
## Your model account
|
|
57
63
|
|
|
@@ -62,8 +68,12 @@ authentication. Verified adapter versions are Codex 0.158.x and Claude Code
|
|
|
62
68
|
verified. This is a native CLI connection, with no Kira account, API-key proxy or
|
|
63
69
|
hosted portfolio backend.
|
|
64
70
|
|
|
65
|
-
In
|
|
66
|
-
|
|
71
|
+
In the 0.1.5 candidate, setup opens the existing Account / Permissions / Ready
|
|
72
|
+
modal directly. Choose Codex or Claude, then Use default model or a readable
|
|
73
|
+
model choice. Codex choices come from bounded native metadata; Claude offers
|
|
74
|
+
Sonnet, Opus and Haiku aliases. A catalog is not proof of account access.
|
|
75
|
+
Advanced accepts a custom identifier and preserves saved identifiers absent
|
|
76
|
+
from the catalog. Workspace settings reopens the same selector and permissions. Choose no automatic wallet context, one registered wallet,
|
|
67
77
|
or the whole recorded portfolio. A generic response check sends no wallet data
|
|
68
78
|
and must pass before these settings are saved.
|
|
69
79
|
|
|
@@ -73,7 +83,10 @@ and contract identities, timestamps, unknown prices and coverage. Credentials,
|
|
|
73
83
|
RPC endpoints, raw provider errors and local paths are excluded. Changing the
|
|
74
84
|
provider, model, context or selected wallet creates a new conversation.
|
|
75
85
|
|
|
76
|
-
|
|
86
|
+
New setup in 0.1.5 recommends saving history and preselects it. Existing saved
|
|
87
|
+
true and false choices are restored exactly. Saving lets you reopen chats after
|
|
88
|
+
restart; it does not expand model memory or wallet access. The choice and
|
|
89
|
+
research permission remain editable in Workspace settings. Kira-local history uses private `conversations/` files. With history
|
|
77
90
|
off, conversations and drafts stay in memory. A new server process starts a fresh
|
|
78
91
|
conversation; saved files remain available locally and are not automatically
|
|
79
92
|
replayed. Native CLI, administrator policy and provider data policies remain a
|
|
@@ -129,8 +142,8 @@ kira config import-env --file /absolute/private/rpc.env --key-env ALCHEMY_API_KE
|
|
|
129
142
|
```
|
|
130
143
|
|
|
131
144
|
The import references the file instead of copying keys. It configures Alchemy
|
|
132
|
-
RPC and portfolio discovery
|
|
133
|
-
|
|
145
|
+
RPC and portfolio discovery together, preserving existing custom chain overrides
|
|
146
|
+
and explicit fallback preferences. New configurations allow public fallback. Environment overrides the file. Missing files or keys
|
|
134
147
|
produce limited coverage; malformed configuration fails with safe errors.
|
|
135
148
|
The import does not contact providers. Private settings are never served.
|
|
136
149
|
|
package/docs/JOB_CONTRACT.md
CHANGED
|
@@ -8,7 +8,8 @@ this contract. Chat interruption never cancels an engine job.
|
|
|
8
8
|
Mutations use `{schema_version: 1, operation, input, idempotency_key}`.
|
|
9
9
|
Supported operations are `wallet.add` (address, exact tag), `wallet.refresh`
|
|
10
10
|
(wallet address or exact tag), `prices.refresh` (same), `wallet.setTags`
|
|
11
|
-
(wallet, exact tags), `
|
|
11
|
+
(wallet, exact tags), `settings.rpc`, `settings.discovery`, `settings.provider`,
|
|
12
|
+
`job.resume` and `job.cancel` (job_id).
|
|
12
13
|
Read operations are `job.read`, `job.list`, `snapshot.read`, and
|
|
13
14
|
`snapshots.compare`. The portfolio projection retains its existing schema.
|
|
14
15
|
|
|
@@ -21,6 +22,17 @@ the same job without rerunning providers. Resume requeues the same job ID and
|
|
|
21
22
|
increments its attempt on execution. Retain the key until the job is removed
|
|
22
23
|
by a future explicit retention policy. Version mismatches fail closed.
|
|
23
24
|
|
|
25
|
+
`settings.provider` accepts exactly `{provider: "public" | "alchemy", key_env}`.
|
|
26
|
+
The key reference is a bounded environment variable name, never a credential.
|
|
27
|
+
One writer-locked atomic replacement changes RPC mode and discovery together.
|
|
28
|
+
Alchemy updates generated network references while preserving explicit custom
|
|
29
|
+
chain overrides, unrelated chains, explorer choice and public fallback policy.
|
|
30
|
+
A missing local key fails before replacement. Public mode keeps inactive custom
|
|
31
|
+
references for later use. A detected key is not a validated provider or complete
|
|
32
|
+
holdings result. Existing settings.rpc and settings.discovery requests remain
|
|
33
|
+
compatible. The browser waits for terminal settings results; retrying a lost
|
|
34
|
+
result checks the same accepted job instead of submitting another change.
|
|
35
|
+
|
|
24
36
|
## Envelope
|
|
25
37
|
|
|
26
38
|
Each private `jobs/<uuid>.json` records schema_version, job_id, operation,
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Token discovery patch acceptance
|
|
2
|
+
|
|
3
|
+
Version: 0.1.4 candidate. Published npm 0.1.3 remains immutable.
|
|
4
|
+
|
|
5
|
+
## Problem and correction
|
|
6
|
+
|
|
7
|
+
A new personal data directory defaults to public RPC and no general ERC20
|
|
8
|
+
indexer. The installed app does not inherit discovery settings from a separate
|
|
9
|
+
research workspace. Public RPC reads native balances and enumerates Mint Club
|
|
10
|
+
assets, but cannot identify arbitrary ERC20 contracts for a wallet. Previously,
|
|
11
|
+
a finished analysis could show only native holdings without explaining this
|
|
12
|
+
configuration at the point of use.
|
|
13
|
+
|
|
14
|
+
The wallet registration dialog now explains limited discovery and offers a
|
|
15
|
+
connection action before research. The wallet overview explains disabled
|
|
16
|
+
discovery, missing credentials, stale analysis or incomplete provider checks.
|
|
17
|
+
It labels incomplete portfolio estimates as partial. Network details retain
|
|
18
|
+
separate discovery, RPC and registry coverage. Read-only and sample views do
|
|
19
|
+
not acquire research permissions.
|
|
20
|
+
|
|
21
|
+
RPC and candidate-balance failures now receive an explicit warning with
|
|
22
|
+
expanded affected-network details. Retry holdings starts the existing gated
|
|
23
|
+
research action; Review RPC settings opens the existing connection dialog.
|
|
24
|
+
The warning says to wait briefly before retrying and review the connection
|
|
25
|
+
or choose another provider if failures persist. Missing balances remain
|
|
26
|
+
unknown. Successful discovery alone cannot mark failed balance reads complete,
|
|
27
|
+
and old snapshots can project their fixed balance-failure note safely.
|
|
28
|
+
|
|
29
|
+
Connecting an indexer does not change an immutable saved analysis. Refresh
|
|
30
|
+
holdings runs discovery again. Refresh prices only updates existing holdings.
|
|
31
|
+
Discovery settings preserve existing explorer preferences, and the UI rereads
|
|
32
|
+
readiness after the settings job succeeds.
|
|
33
|
+
|
|
34
|
+
Registry diagnostics now retain up to five redacted error examples and numeric
|
|
35
|
+
HTTP or RPC codes in local evidence. The public model exposes only status and
|
|
36
|
+
counts. Oversized multicalls split at the same observed block, including errors
|
|
37
|
+
that viem converts into failed result rows. Transport outages and throttling
|
|
38
|
+
remain bounded instead of retrying every contract separately.
|
|
39
|
+
|
|
40
|
+
## Verification
|
|
41
|
+
|
|
42
|
+
- Required `npm test` suite passed: 152 Python tests, required Node behavior
|
|
43
|
+
checks and browser script syntax checks.
|
|
44
|
+
- `scripts/check-install.py` passed with a fresh 73-member package installation
|
|
45
|
+
and startup/shutdown lifecycle in a temporary synthetic workspace.
|
|
46
|
+
- The tracked-source privacy scan passed with the active private data directory
|
|
47
|
+
included. The full-history scan retains the previously recorded non-noreply
|
|
48
|
+
merge identity at `2ed52a2`; no new finding was introduced. That historical
|
|
49
|
+
identity is not reproduced here and public history was not rewritten.
|
|
50
|
+
- Actual viem with an in-memory aggregate3 transport: eight calls rejected
|
|
51
|
+
above two calls per batch succeed in seven requests, all at block 103.
|
|
52
|
+
Independent review also checked that HTTP 429 and 503 stay at one request
|
|
53
|
+
and isolated contract failures remain isolated. No live RPC is used by this
|
|
54
|
+
regression.
|
|
55
|
+
- Missing, unreadable and disabled discovery credentials produce explicit
|
|
56
|
+
coverage status without exposing credentials or attempting discovery.
|
|
57
|
+
- Viewer projection keeps raw provider diagnostics private and preserves
|
|
58
|
+
unknown prices. UI behavior checks cover disabled discovery, missing
|
|
59
|
+
credentials, stale analysis after connection, read-only actions and
|
|
60
|
+
partially successful explorer coverage.
|
|
61
|
+
- RPC recovery regressions cover unavailable chains, registry failures,
|
|
62
|
+
non-Mint candidate-balance failures, mixed missing connections, unknown
|
|
63
|
+
valuations, read-only controls and removal after a successful analysis.
|
|
64
|
+
- Chrome fixture checks at 1440 x 900 and 390 x 844: partial estimate and
|
|
65
|
+
discovery notice render without horizontal overflow. Both connection actions
|
|
66
|
+
open Research connections. The add-wallet dialog says Add with limited
|
|
67
|
+
discovery when the provider is absent. Fixture actions submitted no research,
|
|
68
|
+
account authorization or provider requests.
|
|
69
|
+
- RPC-failure fixtures at the same desktop/mobile sizes show expanded Base
|
|
70
|
+
and BNB Chain details, both recovery actions and a partial estimate without
|
|
71
|
+
horizontal overflow. Review RPC settings opens the connection dialog.
|
|
72
|
+
|
|
73
|
+
The design references were Mixpanel's dashboard connection guidance and
|
|
74
|
+
Databricks' inline data-check failure state, retrieved
|
|
75
|
+
with [Lazyweb](https://www.lazyweb.com/agentic-search/51280761-491a-4a3f-a78e-ed2dcd427ee8).
|
|
76
|
+
No operator wallet information or screenshots were submitted to that service.
|
|
77
|
+
|
|
78
|
+
Independent review found a viem failed-result handling defect during
|
|
79
|
+
implementation. The correction and actual-client regression were reviewed
|
|
80
|
+
again and the finding was closed. Screenshots and operator test evidence
|
|
81
|
+
remain in the ignored local ticket ledger.
|
|
82
|
+
|
|
83
|
+
## Acceptance limits and release boundary
|
|
84
|
+
|
|
85
|
+
Operator-approved reuse of an existing discovery connection recovered
|
|
86
|
+
non-native holdings in a new saved analysis. Some provider and network gaps
|
|
87
|
+
remain; this does not establish complete holdings or verify every expected
|
|
88
|
+
token. Those limits remain visible in coverage. The existing operator server
|
|
89
|
+
was not restarted or globally upgraded during patch verification.
|
|
90
|
+
|
|
91
|
+
The source/package privacy scan is required before preparation.
|
|
92
|
+
`scripts/prepare-release.py`
|
|
93
|
+
pins the clean source commit and archive checksum. Registry publication
|
|
94
|
+
remains operator-only. No npm publication, GitHub release publication or PR
|
|
95
|
+
merge is part of preparing this candidate.
|
|
@@ -4,6 +4,27 @@ Kira connects the user's installed, unmodified Codex or Claude Code CLI. It does
|
|
|
4
4
|
|
|
5
5
|
The setup flow separates account readiness, model choice, context permission, and confirmation. The conversation composer remains visible. It shows the connected CLI, automatic context scope, response state, cancellation, and a new conversation action. Enter sends; Shift+Enter adds a line; composition events never send.
|
|
6
6
|
|
|
7
|
+
`kira setup` opens the existing Account, Permissions and Ready modal directly
|
|
8
|
+
after the local session and workspace are available. Opening setup does not run
|
|
9
|
+
a model response check, save permissions or start wallet research. Existing
|
|
10
|
+
settings are loaded when setup is reopened. Closing the modal consumes that
|
|
11
|
+
page's setup request, so background polling does not reopen it. Ordinary
|
|
12
|
+
`kira start` keeps the normal workspace entry behavior.
|
|
13
|
+
|
|
14
|
+
The 0.1.5 selector defaults to Use default model. Codex uses a bounded stdio
|
|
15
|
+
app-server handshake and model/list request; it never starts a thread or turn.
|
|
16
|
+
The subprocess has an eight-second metadata deadline and 256 KB output bound.
|
|
17
|
+
Metadata failures leave the default and Advanced identifier entry available.
|
|
18
|
+
Only installed supported CLI versions are queried. Claude uses its documented
|
|
19
|
+
Sonnet, Opus and Haiku aliases. Every chosen model still requires a deliberate
|
|
20
|
+
generic response test. Vendor account and managed policies may restrict access.
|
|
21
|
+
Workspace settings reuses this modal for both providers and all permissions.
|
|
22
|
+
Fresh setup preselects local history; existing false values remain false.
|
|
23
|
+
History permits reopening chats, without extending model memory or scope.
|
|
24
|
+
No wallet context permits general chat and manual wallet management while
|
|
25
|
+
wallet context and research tools remain unavailable. Any effective model or
|
|
26
|
+
permission change starts a fresh conversation.
|
|
27
|
+
|
|
7
28
|
Automatic context is none, one explicitly selected registered wallet, or the whole recorded portfolio. An allowlisted projection preserves exact balances, contract and chain identities, timestamps, unknown values, and coverage gaps. It excludes credentials, RPC endpoints, paths, raw errors, jobs, and provider payloads. User-entered text is also sent to the selected provider. Scope, wallet, provider, or model changes start a new conversation and never replay old messages. Only a bounded current conversation is replayed.
|
|
8
29
|
|
|
9
30
|
Approved wallet context can include validated historical full-balance Mint Club
|
|
@@ -53,7 +74,7 @@ in Activity and also appear in the chat tray. Unanalysed wallets show a sidebar
|
|
|
53
74
|
spinner and open Activity while their first holdings job is active.
|
|
54
75
|
|
|
55
76
|
History is capped at 100 memory sessions and reads up to 200 validated local
|
|
56
|
-
files. Saving remains
|
|
77
|
+
files. Saving is recommended for fresh setup and remains an editable choice. Memory sessions disappear when the process stops.
|
|
57
78
|
A previous session can continue only with exactly the same model and context
|
|
58
79
|
configuration. Reading history does not expand model access. Old saved files
|
|
59
80
|
remain readable. No missing memory-only conversations are reconstructed.
|
|
@@ -65,3 +86,15 @@ The receipt is consumed only on success. This does not enable history retention.
|
|
|
65
86
|
The Kira system voice is concise, composed and practical. It leads with findings
|
|
66
87
|
and preserves evidence, unknown values and signing boundaries. Personality is
|
|
67
88
|
prompt guidance; response quality still depends on the selected model.
|
|
89
|
+
|
|
90
|
+
## 0.1.5 preparation evidence
|
|
91
|
+
|
|
92
|
+
The combined settings and model-selection tests cover catalog failures, stale
|
|
93
|
+
responses, custom identifiers, fresh retention defaults, saved opt-outs,
|
|
94
|
+
atomic provider changes, preference preservation, missing keys, cancellation
|
|
95
|
+
and ambiguous receipts. Desktop 1440 × 900 and mobile 390 × 844 checks used an
|
|
96
|
+
empty disposable workspace. Codex 0.158.0 and Claude Code 2.1.293 completed
|
|
97
|
+
native default-model response checks with no wallet data. The provider save
|
|
98
|
+
used a synthetic local key reference and made no provider research request.
|
|
99
|
+
Real extension approval, personal OWS passphrases and live holdings coverage
|
|
100
|
+
are separate operator acceptance. Published 0.1.4 snapshots are not rewritten.
|
package/docs/RELEASE.md
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
GitHub version releases and npm registry publication are separate. The GitHub
|
|
6
6
|
0.1.2 release provides the reviewed `kira-wallet-0.1.2.tgz`, its SHA-256 file and
|
|
7
7
|
release manifest. Its tag pins the source used to create those assets. Install
|
|
8
|
-
that archive from GitHub
|
|
8
|
+
that archive from GitHub. The operator published npm 0.1.3 on 2026-10-06;
|
|
9
|
+
its archive and installed bytes were verified separately. GitHub v0.1.3
|
|
10
|
+
remains a draft. GitHub and registry status must not be inferred from each other.
|
|
9
11
|
Version 0.1.2 was published to GitHub on 2026-10-05 from
|
|
10
12
|
`f994e99acb4e2d778fb4c95479f04355c88c00b3`. Its archive SHA-256 is
|
|
11
13
|
`866b7f1ad543bff1ff59d3bf840eca6313eb6e206e78b8611186e5a971153f28`.
|
|
@@ -21,7 +23,7 @@ their invented wallet addresses, balances and seeded chat are documented in
|
|
|
21
23
|
|
|
22
24
|
## npm publication preparation
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
Published **0.1.3** makes `kira start` open the full local
|
|
25
27
|
app by default. `--read-only` preserves the viewer-only mode, `--no-open`
|
|
26
28
|
supports terminal-only use, and `--controls` remains compatible with existing
|
|
27
29
|
scripts. A running instance never changes modes silently. Local session,
|
|
@@ -30,9 +32,31 @@ creation now identifies Open Wallet Standard with its official locally served
|
|
|
30
32
|
logo and explains encrypted local storage and public-account research. The
|
|
31
33
|
OWS integration and wallet-operation permissions are unchanged.
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
Published **0.1.4** makes incomplete token discovery visible
|
|
36
|
+
before registration and beside wallet holdings, separates disabled discovery
|
|
37
|
+
from missing credentials and provider failures, and offers a connection or
|
|
38
|
+
holdings-refresh action. Registry failures retain bounded redacted examples
|
|
39
|
+
and RPC error codes. Oversized multicalls split into smaller batches while
|
|
40
|
+
transport outages remain bounded. Existing explorer preferences are preserved
|
|
41
|
+
when discovery settings are saved. Connecting an indexer and refreshing
|
|
42
|
+
holdings are still required to recover tokens absent from an older snapshot.
|
|
43
|
+
RPC failures show affected networks, retry guidance and a settings action.
|
|
44
|
+
Failed candidate balance reads keep the saved result and valuation partial
|
|
45
|
+
even when general token discovery succeeded.
|
|
46
|
+
|
|
47
|
+
The next candidate is **0.1.5**. It opens the existing setup modal directly,
|
|
48
|
+
adds readable Codex and Claude model choices, and exposes model and permission
|
|
49
|
+
changes in Workspace settings. New setup recommends local history; upgrades
|
|
50
|
+
preserve explicit opt-outs. Watching wallet methods use individual buttons.
|
|
51
|
+
Data provider connection offers one atomic Alchemy RPC and discovery save,
|
|
52
|
+
with custom overrides under Advanced. A missing key keeps prior settings.
|
|
53
|
+
The wallet draft survives a connection detour. Connecting still requires an
|
|
54
|
+
explicit holdings refresh before missing assets can appear in saved evidence.
|
|
55
|
+
|
|
56
|
+
Version 0.1.5 requires independent review and operator registry publication.
|
|
57
|
+
It is not yet available from the registry. Keep published 0.1.4 and earlier
|
|
58
|
+
package bytes immutable. The showcase remains a separate deployment.
|
|
59
|
+
See [discovery acceptance](KIRA_DISCOVERY_ACCEPTANCE.md).
|
|
36
60
|
|
|
37
61
|
The operator published npm **0.1.2** on 2026-10-05. Its registry archive was
|
|
38
62
|
downloaded and matched the reviewed GitHub archive above, including SHA-256,
|
|
@@ -54,8 +78,7 @@ The earlier unpublished 0.1.2 candidate is preserved in the ignored
|
|
|
54
78
|
`dist/preserved-0.1.2-bad8f02/` directory. Use the current `dist/release.json`
|
|
55
79
|
and its matching archive for publication; do not mix manifests from candidates.
|
|
56
80
|
|
|
57
|
-
Keep GitHub v0.1.1, its tag and its released archive immutable.
|
|
58
|
-
is also released and immutable. Do not rebuild it from later documentation
|
|
81
|
+
Keep GitHub v0.1.1, its tag and its released archive immutable. Versions 0.1.2, 0.1.3 and 0.1.4 are also published and immutable. Do not rebuild them from later documentation
|
|
59
82
|
commits. Future package changes need a new version. Release preparation does not
|
|
60
83
|
publish a GitHub release, merge PR 19, promote the website or publish to npm.
|
|
61
84
|
Registry publication remains operator-only. The coding agent never publishes.
|
|
@@ -70,12 +93,12 @@ python3 scripts/prepare-release.py
|
|
|
70
93
|
```
|
|
71
94
|
|
|
72
95
|
`prepare-release.py` scans the package boundary and creates
|
|
73
|
-
`dist/kira-wallet-0.1.
|
|
96
|
+
`dist/kira-wallet-0.1.5.tgz`. The ignored `dist/release.json` records its source
|
|
74
97
|
commit, SHA-256 and member count. It never publishes. After reviewing that
|
|
75
98
|
manifest, the operator's final command from the project root is:
|
|
76
99
|
|
|
77
100
|
```sh
|
|
78
|
-
npm publish ./dist/kira-wallet-0.1.
|
|
101
|
+
npm publish ./dist/kira-wallet-0.1.5.tgz --access public
|
|
79
102
|
```
|
|
80
103
|
|
|
81
104
|
Use the operator's npm account and complete authentication or OTP personally.
|
package/kira_agent.py
CHANGED
|
@@ -251,6 +251,7 @@ class AgentStore:
|
|
|
251
251
|
self.root = Path(root);self.path = self.root/'.kira-agent.json';self.runner=runner;self.detector=detector
|
|
252
252
|
self.lock=threading.RLock();self.turns={};self.active=None;self.epoch=0;self.messages=[];self.conversation=str(uuid.uuid4());self.tested=set();self.config=None;self.workers=[];self.tool_status=None
|
|
253
253
|
self._capabilities=None;self._checked=0
|
|
254
|
+
self._model_lock=threading.Lock();self._model_cache={}
|
|
254
255
|
self.sessions={};self.started_at=datetime.now(timezone.utc).isoformat();self.updated_at=self.started_at
|
|
255
256
|
if self.path.exists():
|
|
256
257
|
try: self.config=config_input(json.loads(self.path.read_text()),self.root)
|
|
@@ -344,6 +345,19 @@ class AgentStore:
|
|
|
344
345
|
self._capabilities=self.detector();self._checked=time.monotonic()
|
|
345
346
|
with self.lock:return {'config':self.config,'providers':self._capabilities,'conversation_id':self.conversation,'messages':self.messages.copy(),'active_turn':self.active,'tool_status':self.tool_status}
|
|
346
347
|
|
|
348
|
+
def models(self, provider, recheck=False):
|
|
349
|
+
if provider not in PROVIDERS:raise JobError('invalid_provider','Choose Codex or Claude.')
|
|
350
|
+
with self._model_lock:
|
|
351
|
+
row=next((row for row in self.status(recheck)['providers'] if row['id']==provider),None)
|
|
352
|
+
if not row or not row['installed'] or not row['supported']:
|
|
353
|
+
return {'models':[], 'note':'Install a supported CLI to load model choices. The default model remains available.'}
|
|
354
|
+
cached=self._model_cache.get(provider)
|
|
355
|
+
if not recheck and cached and time.monotonic()-cached[0]<60:return cached[1]
|
|
356
|
+
from kira_models import catalog
|
|
357
|
+
result=catalog(provider)
|
|
358
|
+
self._model_cache[provider]=(time.monotonic(),result)
|
|
359
|
+
return result
|
|
360
|
+
|
|
347
361
|
def fingerprint(self,config):return hashlib.sha256(json.dumps(config,sort_keys=True).encode()).hexdigest()
|
|
348
362
|
|
|
349
363
|
def stop(self):
|
package/kira_cli.py
CHANGED
|
@@ -232,10 +232,9 @@ def main():
|
|
|
232
232
|
if args.command=='config':
|
|
233
233
|
file=Path(args.file).expanduser().resolve()
|
|
234
234
|
if not file.is_file():raise ValueError('Secret environment file does not exist.')
|
|
235
|
-
from
|
|
236
|
-
cfg
|
|
237
|
-
cfg['
|
|
238
|
-
'chains':{str(cid):{'url_env':args.key_env,'alchemy_network':name} for cid,name in ALCHEMY.items()}}
|
|
235
|
+
from kira_config import provider_config
|
|
236
|
+
cfg=provider_config(cfg,'alchemy',args.key_env)
|
|
237
|
+
cfg['secret_env_file']=str(file);cfg['discovery']['explorers']=True
|
|
239
238
|
elif args.command=='discovery':cfg['discovery']={'provider':args.provider,'key_env':args.key_env,'explorers':args.explorers}
|
|
240
239
|
elif args.setting=='public':cfg['rpc']['mode']='public'
|
|
241
240
|
else:
|
package/kira_config.py
CHANGED
|
@@ -19,6 +19,19 @@ def default_config():
|
|
|
19
19
|
return {'schema_version':1,'rpc':{'mode':'public','allow_public_fallback':True,'chains':{}},
|
|
20
20
|
'discovery':{'provider':'none','key_env':'ALCHEMY_API_KEY','explorers':False}}
|
|
21
21
|
|
|
22
|
+
def provider_config(config, provider, key_env):
|
|
23
|
+
"""One settings transition. Preserve explicit fallback and custom overrides."""
|
|
24
|
+
result={**config,'rpc':{**config['rpc'],'chains':{cid:dict(row) for cid,row in config['rpc']['chains'].items()}},
|
|
25
|
+
'discovery':{**config['discovery'],'provider':'alchemy' if provider=='alchemy' else 'none','key_env':key_env}}
|
|
26
|
+
result['rpc']['mode']='custom' if provider=='alchemy' else 'public'
|
|
27
|
+
if provider=='alchemy':
|
|
28
|
+
from wallet import ALCHEMY
|
|
29
|
+
for cid,network in ALCHEMY.items():
|
|
30
|
+
previous=result['rpc']['chains'].get(str(cid))
|
|
31
|
+
if not previous or previous.get('alchemy_network'):
|
|
32
|
+
result['rpc']['chains'][str(cid)]={'url_env':key_env,'alchemy_network':network}
|
|
33
|
+
return result
|
|
34
|
+
|
|
22
35
|
def load_config():
|
|
23
36
|
path=config_path()
|
|
24
37
|
if not path.exists():return default_config()
|
package/kira_jobs.py
CHANGED
|
@@ -19,7 +19,7 @@ import uuid
|
|
|
19
19
|
|
|
20
20
|
ASSETS = Path(__file__).resolve().parent
|
|
21
21
|
State = Literal['queued', 'running', 'interrupted', 'succeeded', 'partial', 'failed', 'cancelled']
|
|
22
|
-
Operation = Literal['wallet.add','wallet.refresh','prices.refresh','wallet.setTags','settings.rpc','settings.discovery']
|
|
22
|
+
Operation = Literal['wallet.add','wallet.refresh','prices.refresh','wallet.setTags','settings.rpc','settings.discovery','settings.provider']
|
|
23
23
|
TERMINAL = {'succeeded', 'partial', 'failed', 'cancelled', 'interrupted'}
|
|
24
24
|
ADDRESS = re.compile(r'0x[0-9a-fA-F]{40}')
|
|
25
25
|
|
|
@@ -124,10 +124,10 @@ class JobStore:
|
|
|
124
124
|
if not isinstance(job,dict) or type(job.get('schema_version')) is not int or job.get('schema_version') != 1: raise JobError('unsupported_version', 'Unsupported persisted job version.')
|
|
125
125
|
required={'schema_version','job_id','operation','input','state','attempt','sequence','result','previous_result','key_hash','request_hash','created_at','updated_at','cancel_requested','checkpoint','stage','events','errors','chains'}
|
|
126
126
|
optional={'raw_hash','control_receipts','control_raw','provider_configuration','started_at'}
|
|
127
|
-
if required-set(job) or set(job)-required-optional or job['job_id']!=job_id or job['checkpoint']!='snapshots/jobs/'+job_id or not isinstance(job['operation'],str) or job['operation'] not in {'wallet.add','wallet.refresh','prices.refresh','wallet.setTags','settings.rpc','settings.discovery'} or not isinstance(job['state'],str) or job['state'] not in TERMINAL|{'queued','running'} or any(type(job[k]) is not int or job[k]<0 for k in ('attempt','sequence')) or type(job['cancel_requested']) is not bool or not isinstance(job['input'],dict) or any(not isinstance(job[k],list) for k in ('events','errors')) or not isinstance(job['chains'],dict):
|
|
127
|
+
if required-set(job) or set(job)-required-optional or job['job_id']!=job_id or job['checkpoint']!='snapshots/jobs/'+job_id or not isinstance(job['operation'],str) or job['operation'] not in {'wallet.add','wallet.refresh','prices.refresh','wallet.setTags','settings.rpc','settings.discovery','settings.provider'} or not isinstance(job['state'],str) or job['state'] not in TERMINAL|{'queued','running'} or any(type(job[k]) is not int or job[k]<0 for k in ('attempt','sequence')) or type(job['cancel_requested']) is not bool or not isinstance(job['input'],dict) or any(not isinstance(job[k],list) for k in ('events','errors')) or not isinstance(job['chains'],dict):
|
|
128
128
|
raise JobError('invalid_envelope','Persisted job validation failed. Preserve the file for recovery.')
|
|
129
129
|
names={'wallet.add':['address','tag'],'wallet.refresh':['wallet'],'prices.refresh':['wallet'],'wallet.setTags':['wallet','tags'],
|
|
130
|
-
'settings.rpc':['mode','chains','allow_public_fallback'],'settings.discovery':['provider','key_env']}[job['operation']]
|
|
130
|
+
'settings.rpc':['mode','chains','allow_public_fallback'],'settings.discovery':['provider','key_env'],'settings.provider':['provider','key_env']}[job['operation']]
|
|
131
131
|
fields(job['input'],names)
|
|
132
132
|
wallet=job['input'].get('wallet') or job['input'].get('address')
|
|
133
133
|
if wallet is not None and (not isinstance(wallet,str) or not ADDRESS.fullmatch(wallet)):raise JobError('invalid_envelope','Persisted wallet identity is invalid.')
|
|
@@ -154,6 +154,11 @@ class JobStore:
|
|
|
154
154
|
return matches[0]
|
|
155
155
|
|
|
156
156
|
def normalize(self, operation, value):
|
|
157
|
+
if operation == 'settings.provider':
|
|
158
|
+
fields(value,['provider','key_env'])
|
|
159
|
+
if value['provider'] not in ('public','alchemy') or not isinstance(value['key_env'],str) or not re.fullmatch(r'[A-Z_][A-Z0-9_]{0,99}',value['key_env']):
|
|
160
|
+
raise JobError('invalid_settings','Choose a data provider and a local credential reference.')
|
|
161
|
+
return value.copy()
|
|
157
162
|
if operation == 'settings.rpc':
|
|
158
163
|
fields(value,['mode','chains','allow_public_fallback'])
|
|
159
164
|
if value['mode'] not in ('public','custom') or type(value['allow_public_fallback']) is not bool or not isinstance(value['chains'],list) or len(value['chains'])>30:
|
|
@@ -403,7 +408,12 @@ class JobStore:
|
|
|
403
408
|
previous=config['rpc']['chains'].get(key,{})
|
|
404
409
|
if row['url_env']==previous.get('url_env') and previous.get('alchemy_network'):row['alchemy_network']=previous['alchemy_network']
|
|
405
410
|
config['rpc']=updated
|
|
406
|
-
|
|
411
|
+
elif job['operation']=='settings.discovery':config['discovery']={**job['input'],'explorers':config['discovery'].get('explorers',False)}
|
|
412
|
+
else:
|
|
413
|
+
from kira_config import provider_config,secret_values
|
|
414
|
+
config=provider_config(config,**job['input'])
|
|
415
|
+
if job['input']['provider']=='alchemy' and not secret_values(config).get(job['input']['key_env']):
|
|
416
|
+
raise JobError('connection_key_missing','Kira cannot find the local Alchemy key. Follow the connection guide, then retry. Existing settings are unchanged.')
|
|
407
417
|
atomic(config_path(),config)
|
|
408
418
|
result={'status':'completed','setting':job['operation']};atomic(self.jobs/'results'/(job['job_id']+'.json'),result);return result
|
|
409
419
|
env = {**os.environ, 'KIRA_DATA_DIR': str(self.root), 'KIRA_JOB_ID': job['job_id'], 'KIRA_JOB_SNAPSHOT': job['checkpoint'], 'KIRA_ANALYSIS_FD': str(writer.fileno()), 'PYTHONUNBUFFERED': '1'}
|
package/kira_models.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Bounded native model metadata. No inference, threads or credential copying."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import selectors
|
|
6
|
+
import shutil
|
|
7
|
+
import signal
|
|
8
|
+
import subprocess
|
|
9
|
+
import tempfile
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
MODEL = re.compile(r'[a-zA-Z0-9._:/-]{1,100}')
|
|
13
|
+
|
|
14
|
+
def clean_catalog(rows):
|
|
15
|
+
result=[]; seen=set()
|
|
16
|
+
if not isinstance(rows,list):return result
|
|
17
|
+
for row in rows[:100]:
|
|
18
|
+
if not isinstance(row,dict) or row.get('hidden'):continue
|
|
19
|
+
model=row.get('model') or row.get('id')
|
|
20
|
+
if not isinstance(model,str) or not MODEL.fullmatch(model) or model in seen:continue
|
|
21
|
+
name=row.get('displayName') or model
|
|
22
|
+
if not isinstance(name,str):name=model
|
|
23
|
+
name=' '.join(name.split())[:100]
|
|
24
|
+
result.append({'id':model,'name':name or model});seen.add(model)
|
|
25
|
+
if len(result)==40:break
|
|
26
|
+
return result
|
|
27
|
+
|
|
28
|
+
def codex_catalog(path, env, *, timeout=8):
|
|
29
|
+
from kira_agent import CODEX_DISABLED
|
|
30
|
+
argv=[path,'app-server','--listen','stdio://','-c','analytics.enabled=false',
|
|
31
|
+
'-c','history.persistence="none"','-c','mcp_servers={}', '-c','model_provider="openai"']
|
|
32
|
+
for feature in CODEX_DISABLED:argv+=['-c',f'features.{feature}=false']
|
|
33
|
+
with tempfile.TemporaryDirectory(prefix='kira-models-') as cwd:
|
|
34
|
+
child=subprocess.Popen(argv,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.DEVNULL,
|
|
35
|
+
cwd=cwd,env=env,start_new_session=True)
|
|
36
|
+
selector=selectors.DefaultSelector();selector.register(child.stdout,selectors.EVENT_READ)
|
|
37
|
+
def send(value):
|
|
38
|
+
child.stdin.write((json.dumps(value)+'\n').encode());child.stdin.flush()
|
|
39
|
+
try:
|
|
40
|
+
send({'id':1,'method':'initialize','params':{'clientInfo':{'name':'kira_model_picker','version':'0.1.5'}}})
|
|
41
|
+
deadline=time.monotonic()+timeout;buffer=b'';received=0;requested=False
|
|
42
|
+
while time.monotonic()<deadline:
|
|
43
|
+
for key,_ in selector.select(min(.2,max(0,deadline-time.monotonic()))):
|
|
44
|
+
chunk=os.read(key.fileobj.fileno(),65536)
|
|
45
|
+
if not chunk:raise ValueError('Catalog ended.')
|
|
46
|
+
received+=len(chunk)
|
|
47
|
+
if received>262144:raise ValueError('Catalog too large.')
|
|
48
|
+
buffer+=chunk
|
|
49
|
+
while b'\n' in buffer:
|
|
50
|
+
line,buffer=buffer.split(b'\n',1)
|
|
51
|
+
try:message=json.loads(line)
|
|
52
|
+
except ValueError:continue
|
|
53
|
+
if not isinstance(message,dict):continue
|
|
54
|
+
if message.get('id')==1 and not requested:
|
|
55
|
+
if 'error' in message:raise ValueError('Initialization failed.')
|
|
56
|
+
requested=True
|
|
57
|
+
send({'method':'initialized'})
|
|
58
|
+
send({'id':2,'method':'model/list','params':{'limit':100,'includeHidden':False}})
|
|
59
|
+
elif message.get('id')==2 and requested:
|
|
60
|
+
if 'error' in message:raise ValueError('Catalog unavailable.')
|
|
61
|
+
result=message.get('result')
|
|
62
|
+
return clean_catalog(result.get('data')) if isinstance(result,dict) else []
|
|
63
|
+
raise TimeoutError('Catalog timed out.')
|
|
64
|
+
finally:
|
|
65
|
+
selector.close()
|
|
66
|
+
try:os.killpg(child.pid,signal.SIGTERM)
|
|
67
|
+
except ProcessLookupError:pass
|
|
68
|
+
try:child.wait(timeout=2)
|
|
69
|
+
except subprocess.TimeoutExpired:
|
|
70
|
+
try:os.killpg(child.pid,signal.SIGKILL)
|
|
71
|
+
except ProcessLookupError:pass
|
|
72
|
+
child.wait()
|
|
73
|
+
child.stdin.close();child.stdout.close()
|
|
74
|
+
|
|
75
|
+
def catalog(provider):
|
|
76
|
+
from kira_agent import native_env
|
|
77
|
+
if provider=='claude':
|
|
78
|
+
return {'models':[{'id':'sonnet','name':'Sonnet'}, {'id':'opus','name':'Opus'}, {'id':'haiku','name':'Haiku'}],
|
|
79
|
+
'note':'Claude CLI model choices. Check a response to verify access for your account.'}
|
|
80
|
+
if provider!='codex':raise ValueError('Unsupported provider.')
|
|
81
|
+
try:
|
|
82
|
+
path=shutil.which('codex')
|
|
83
|
+
models=codex_catalog(path,native_env()) if path else []
|
|
84
|
+
except (OSError,ValueError,TypeError,TimeoutError):models=[]
|
|
85
|
+
return {'models':models,'note':'CLI catalog choices. Check a response to verify account access.' if models else
|
|
86
|
+
'Model choices are unavailable. Use the default model, recheck, or enter an ID under Advanced.'}
|
package/onchain.cjs
CHANGED
|
@@ -52,7 +52,12 @@ function safeError(error){
|
|
|
52
52
|
message=message.replace(/https?:\/\/[^\s"<>]+/g,'[RPC URL]');
|
|
53
53
|
message=message.replace(/(bearer\s+)[^\s,;"<>]+/gi,'$1[redacted]');
|
|
54
54
|
message=message.replace(/(authorization|api[-_]?key|bearer)([\s:=]+)[^\s,;"<>]+/gi,'$1$2[redacted]');
|
|
55
|
-
|
|
55
|
+
const diagnostic={error_type:error.name,message:message.slice(0,500)};
|
|
56
|
+
for(let cause=error,depth=0;cause&&depth<6;cause=cause.cause,depth++){
|
|
57
|
+
if(Number.isInteger(cause.status))diagnostic.http_status=cause.status;
|
|
58
|
+
if(Number.isInteger(cause.code))diagnostic.rpc_code=cause.code;
|
|
59
|
+
}
|
|
60
|
+
return diagnostic;
|
|
56
61
|
}
|
|
57
62
|
function rpcEndpointsUsed(c){return [...(endpointReads.get(c)||[])].filter(i=>i>=0).sort((a,b)=>a-b);}
|
|
58
63
|
module.exports={viem,root,assets,networks,bondAbi,endpoints,client,connect,resilientTransport,rpcEndpointsUsed,serialize,safeError};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kira-wallet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Manage your wallets with your own AI. Track tokens, research markets and refresh holdings in a local workspace.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -55,7 +55,9 @@
|
|
|
55
55
|
"kira_research_tools.py",
|
|
56
56
|
"kira_ows.py",
|
|
57
57
|
"ows_bridge.cjs",
|
|
58
|
-
"docs/KIRA_LIVE_QA.md"
|
|
58
|
+
"docs/KIRA_LIVE_QA.md",
|
|
59
|
+
"docs/KIRA_DISCOVERY_ACCEPTANCE.md",
|
|
60
|
+
"kira_models.py"
|
|
59
61
|
],
|
|
60
62
|
"scripts": {
|
|
61
63
|
"test": "python3 -m unittest discover -s . -p 'test_*.py' && python3 -m unittest discover -s viewer -p 'test_*.py' && node test-onchain.cjs && node --check viewer/static/app.js && node --check viewer/static/jobs.js && node test-workspace.cjs && node --check viewer/static/workspace.js && node --check viewer/static/workspace-model.js && node test-watching.cjs && node test-watching-ui.cjs && node --check viewer/static/watching.js && node --check viewer/static/watching-model.js && node --check viewer/static/agent.js && node test-agent-ui.cjs && node test-markdown.cjs && node --check viewer/static/report.js && node test-report-ui.cjs && node test-holdings-ui.cjs && node test-rpc-fallback.cjs && node test-ows.cjs && node test-ows-ui.cjs && node --check viewer/static/ows.js && node --check viewer/static/chat-workspace.js && node --check viewer/static/selects.js && node --check site/demo.js"
|