Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9c0706e
chore(protected-content): prepare provisioning dependencies and docum…
irzhywau Sep 2, 2026
4d688cc
feat(protected-content): provision installed custody and chain prereq…
irzhywau Sep 2, 2026
5675b88
feat(home): first run seeds an empty desktop and pins Marketplace
SashaMIT Sep 2, 2026
568bb04
test(home): regression smoke expects the empty first-run desktop
SashaMIT Sep 2, 2026
d8c37cb
fix(apps): clear the unified-sidebar chrome overlay in Documents, Inb…
SashaMIT Sep 2, 2026
90d7f08
fix(inbox): request rows hug their content instead of stretching to t…
SashaMIT Sep 2, 2026
b26f5ee
feat(home): lock face — wordmark, full-bleed ground and vignette, lar…
SashaMIT Sep 2, 2026
ecb6ecd
feat(documents): flat unified-sidebar layout
SashaMIT Sep 2, 2026
ba95c94
feat(library): New and Upload move into the toolbar menu
SashaMIT Sep 2, 2026
f175b70
feat(home): dock motion — eased pill width, height-led Apps reveal, l…
SashaMIT Sep 2, 2026
8c39c89
feat(home): Apps face at dock width, URUX motion tokens
SashaMIT Sep 2, 2026
05ff77b
fix(home): Apps face uncovers planted icons and never repeats the doc…
SashaMIT Sep 2, 2026
37bd411
fix(home): Apps face keeps the dock row on the floor through open and…
SashaMIT Sep 2, 2026
c9a4a66
fix(home): dock renders at final width on load; icons never leave the…
SashaMIT Sep 2, 2026
2a49ea5
feat(providers): service capsules own their Marketplace icons
SashaMIT Sep 3, 2026
0dc5b40
fix(protected-content): verify custody node provisioning via installe…
andersalm Sep 3, 2026
68fe34c
fix(home): restore first-run hint and CSS spacing
andersalm Sep 3, 2026
b49a5dc
fix(setup): package provider capsule metadata
andersalm Sep 3, 2026
c90ba87
merge: add verified protected content provisioning
andersalm Sep 3, 2026
64449ae
merge: package provider catalog metadata
andersalm Sep 3, 2026
4d9cb29
docs: record 0.7.1 development truth
andersalm Sep 3, 2026
37b4195
fix(runtime): resolve managed providers from installed bin
andersalm Sep 3, 2026
7b61913
docs: align 0.7.1 candidate review state
andersalm Sep 4, 2026
4383992
feat(runtime): Home Agent capsule gets a workspace object and its own…
SashaMIT Sep 3, 2026
498dab2
feat(home): the Shelf morphs into the Agent composer and opens the Ag…
SashaMIT Sep 3, 2026
7749855
feat(home-agent): the agent harness as its own capsule, on the typed …
SashaMIT Sep 3, 2026
47a44df
test(home-agent): capsule gate for the typed contract, the workspace …
SashaMIT Sep 3, 2026
450db53
fix(home-agent): bind capsule handoffs to Home
andersalm Sep 4, 2026
9e31558
fix(deps): refresh object-provider lock after provisioning
andersalm Sep 4, 2026
900d7e5
fix(home): unify Agent launch and layout upgrades
andersalm Sep 4, 2026
e108dd3
docs: record 0.7.1 candidate acceptance
andersalm Sep 4, 2026
f8c167f
docs(model): define inference placement and delivery plan
andersalm Sep 4, 2026
12d3826
docs(model): separate responses from agent execution
andersalm Sep 4, 2026
5ba1faa
fix(setup): satisfy clippy question_mark on the extracted-bundle guard
irzhywau Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,14 @@ capsules, provider config, and `components.json`.
- Avoid volatile proof logs in durable docs. Store open work in `TASKS.md`,
verified current truth in `state.md`, and release history in
`elastos/CHANGELOG.md`.
- Keep standing instructions, READMEs, contracts and roadmaps independent of
the current release. Branch heads, PR numbers, commit IDs, CI results and
installation snapshots belong in `state.md` or a dated evidence record.
Contract versions, dependency pins and artifact provenance stay with the
contract or artifact they identify.
- Keep product documentation release-neutral. Use version numbers only for
exact release state, compatibility or migration, release notes or changelogs,
manifests, and exact Git refs or evidence. Keep standing instructions,
READMEs, contracts, and roadmaps independent of the current release.
Branch heads, PR numbers, commit IDs, CI results, and installation snapshots
belong in `state.md` or a dated evidence record. Contract versions,
dependency pins, and artifact provenance stay with the contract or artifact
they identify.

## Verification Gate

Expand Down
173 changes: 99 additions & 74 deletions TASKS.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions capsules/browser-engine-adapter/capsule.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"role": "provider",
"type": "microvm",
"entrypoint": "rootfs.ext4",
"icon": "icons",
"provides": "elastos://browser-engine/*",
"authority": {
"reason": "Defines the internal browser-engine adapter contract without exposing raw sockets, host browser APIs, wallet injection, filesystem access, or host internet access to app capsules.",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added capsules/browser-engine-adapter/icons/icon-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added capsules/browser-engine-adapter/icons/icon-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions capsules/chain-provider/capsule.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"role": "provider",
"type": "microvm",
"entrypoint": "rootfs.ext4",
"icon": "icons",
"provides": "elastos://chain/*",
"authority": {
"reason": "Provides typed chain status, proofs, transaction intents, broadcasts, and managed node lifecycle without exposing raw node RPC URLs to app capsules.",
Expand Down
Binary file added capsules/chain-provider/icons/icon-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added capsules/chain-provider/icons/icon-256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added capsules/chain-provider/icons/icon-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added capsules/chain-provider/icons/icon-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion capsules/chat-room/browser/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ p {
min-height: 0;
flex-direction: column;
gap: 0.45rem;
padding: 12px 10px 14px;
/* Unified-sidebar chrome paints the traffic lights over the first 52px;
capsule-local value on purpose (see home-entropy-check: Chat/Inbox). */
padding: 52px 10px 14px;
overflow: auto;
border-right: 1px solid color-mix(in srgb, var(--line) 55%, transparent);
background: var(--sidebar-bg);
Expand Down
1 change: 1 addition & 0 deletions capsules/content-block-graph-provider/capsule.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"role": "provider",
"type": "microvm",
"entrypoint": "rootfs.ext4",
"icon": "icons",
"provides": "elastos://block-graph/*",
"authority": {
"reason": "Exports and imports bounded content block graphs for provider-to-provider repair without exposing raw Kubo/IPFS, filesystem, or peer authority to app capsules.",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
124 changes: 7 additions & 117 deletions capsules/custody-provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ use std::io::{Read as _, Write as _};
use std::path::{Component, Path, PathBuf};

use ed25519_dalek::SigningKey;
use elastos_protected_content_contracts::{
NodeCustodyPublicKeyV1, NodePublicKey, RuntimeOperationIssuerKeyV1,
PQ_HYBRID_WRAP_PUBLIC_KEY_BYTES,
};
use elastos_protected_content_contracts::{NodePublicKey, RuntimeOperationIssuerKeyV1};
use elastos_protected_content_custody::NodeCustodySecretKeyV1;
pub use elastos_protected_content_provider_contracts::{
parse_and_verify_provisioning_output, provisioning_receipt,
ProvisionedCustodyProviderPublicKeys, ProvisioningOutputError,
CUSTODY_PROVIDER_PROVISIONING_RECEIPT_PROVIDER_ID_V1 as PROVISIONING_PROVIDER_ID,
CUSTODY_PROVIDER_PROVISIONING_RECEIPT_SCHEMA_V1 as PROVISIONING_SCHEMA_V1,
};
use serde::Deserialize;
use zeroize::Zeroizing;

Expand All @@ -18,8 +21,6 @@ const TRUSTED_RUNTIME_ISSUER_FILE: &str = "trusted-runtime-issuer";
const NODE_CUSTODY_SECRET_FILE: &str = "node-custody-secret";
const NODE_SIGNING_KEY_FILE: &str = "node-signing-key";
const DATA_ROOT_DIR: &str = "data";
pub const PROVISIONING_SCHEMA_V1: &str = "elastos.custody-provider.provisioning-receipt/v1";
pub const PROVISIONING_PROVIDER_ID: &str = "custody";

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CustodyProviderStateRootError {
Expand Down Expand Up @@ -50,29 +51,6 @@ pub struct LoadedCustodyProviderState {
pub data_root: PathBuf,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProvisionedCustodyProviderPublicKeys {
pub node_public_key: NodePublicKey,
pub node_custody_public_key: NodeCustodyPublicKeyV1,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProvisioningOutputError {
InvalidOutput,
InvalidReceipt,
}

impl std::fmt::Display for ProvisioningOutputError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str(match self {
Self::InvalidOutput => "custody provider provisioning output is invalid",
Self::InvalidReceipt => "custody provider provisioning receipt is invalid",
})
}
}

impl std::error::Error for ProvisioningOutputError {}

#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
struct ProviderInitConfigV1 {
Expand Down Expand Up @@ -132,74 +110,6 @@ pub fn parse_runtime_issuer_hex(
.map_err(|_| CustodyProviderStateRootError::InvalidConfig)
}

pub fn provisioning_receipt(
runtime_issuer: RuntimeOperationIssuerKeyV1,
node_public_key: NodePublicKey,
node_custody_public_key: NodeCustodyPublicKeyV1,
) -> [u8; 32] {
use sha2::Digest as _;

let mut hasher = sha2::Sha256::new();
hasher.update(PROVISIONING_SCHEMA_V1.as_bytes());
hasher.update(runtime_issuer.as_bytes());
hasher.update(node_public_key.as_bytes());
hasher.update(node_custody_public_key.as_bytes());
hasher.finalize().into()
}

pub fn parse_and_verify_provisioning_output(
value: &serde_json::Value,
expected_runtime_issuer: RuntimeOperationIssuerKeyV1,
) -> Result<ProvisionedCustodyProviderPublicKeys, ProvisioningOutputError> {
let object = value
.as_object()
.ok_or(ProvisioningOutputError::InvalidOutput)?;
if object.len() != 2 || object.get("status").and_then(serde_json::Value::as_str) != Some("ok") {
return Err(ProvisioningOutputError::InvalidOutput);
}
let data = object
.get("data")
.and_then(serde_json::Value::as_object)
.ok_or(ProvisioningOutputError::InvalidOutput)?;
if data.len() != 5
|| data.get("schema").and_then(serde_json::Value::as_str) != Some(PROVISIONING_SCHEMA_V1)
|| data.get("provider").and_then(serde_json::Value::as_str)
!= Some(PROVISIONING_PROVIDER_ID)
{
return Err(ProvisioningOutputError::InvalidOutput);
}
let node_public_key = NodePublicKey::new(parse_exact_hex_bytes::<32>(
data.get("node_public_key")
.and_then(serde_json::Value::as_str)
.ok_or(ProvisioningOutputError::InvalidOutput)?,
)?)
.map_err(|_| ProvisioningOutputError::InvalidOutput)?;
let node_custody_public_key =
NodeCustodyPublicKeyV1::new(parse_exact_hex_bytes::<PQ_HYBRID_WRAP_PUBLIC_KEY_BYTES>(
data.get("node_custody_public_key")
.and_then(serde_json::Value::as_str)
.ok_or(ProvisioningOutputError::InvalidOutput)?,
)?)
.map_err(|_| ProvisioningOutputError::InvalidOutput)?;
let receipt = parse_exact_hex_bytes::<32>(
data.get("receipt")
.and_then(serde_json::Value::as_str)
.ok_or(ProvisioningOutputError::InvalidOutput)?,
)?;
let expected = provisioning_receipt(
expected_runtime_issuer,
node_public_key,
node_custody_public_key,
);
if receipt != expected {
return Err(ProvisioningOutputError::InvalidReceipt);
}
Ok(ProvisionedCustodyProviderPublicKeys {
node_public_key,
node_custody_public_key,
})
}

pub fn validate_state_root_path(root: &Path) -> Result<(), CustodyProviderStateRootError> {
validate_absolute_path_syntax(root)?;
validate_existing_path_components(root)?;
Expand Down Expand Up @@ -339,26 +249,6 @@ fn create_stage_root(parent: &Path) -> Result<PathBuf, CustodyProviderStateRootE
Err(CustodyProviderStateRootError::ProvisioningFailed)
}

fn parse_exact_hex_bytes<const N: usize>(value: &str) -> Result<[u8; N], ProvisioningOutputError> {
let hex = value
.strip_prefix("0x")
.ok_or(ProvisioningOutputError::InvalidOutput)?;
if hex.len() != N * 2
|| !hex
.bytes()
.all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase())
{
return Err(ProvisioningOutputError::InvalidOutput);
}
let mut decoded = [0u8; N];
for (index, pair) in hex.as_bytes().chunks_exact(2).enumerate() {
decoded[index] =
(hex_nibble(pair[0]).map_err(|_| ProvisioningOutputError::InvalidOutput)? << 4)
| hex_nibble(pair[1]).map_err(|_| ProvisioningOutputError::InvalidOutput)?;
}
Ok(decoded)
}

fn remove_created_stage_root(path: &Path) -> Result<(), CustodyProviderStateRootError> {
let file_name = path
.file_name()
Expand Down
1 change: 1 addition & 0 deletions capsules/did-provider/capsule.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"role": "provider",
"type": "microvm",
"entrypoint": "rootfs.ext4",
"icon": "icons",
"provides": "elastos://did/*",
"authority": {
"reason": "Mediates device-backed DID identity and local persona metadata from runtime-managed identity storage.",
Expand Down
Binary file added capsules/did-provider/icons/icon-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added capsules/did-provider/icons/icon-256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added capsules/did-provider/icons/icon-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added capsules/did-provider/icons/icon-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading