Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion src/commands/airc/send/browser/AircSendBrowserCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
*/

import { CommandBase, type ICommandDaemon } from '@daemons/command-daemon/shared/CommandBase';
import type { JTAGContext } from '@system/core/types/JTAGTypes';
import type { CommandScope, JTAGContext } from '@system/core/types/JTAGTypes';
import type { AircSendParams, AircSendResult } from '../shared/AircSendTypes';

export class AircSendBrowserCommand extends CommandBase<AircSendParams, AircSendResult> {
protected static override get naturalScope(): CommandScope {
return { type: 'room' };
}

constructor(context: JTAGContext, subpath: string, commander: ICommandDaemon) {
super('airc/send', context, subpath, commander);
Expand Down
5 changes: 4 additions & 1 deletion src/commands/airc/send/server/AircSendServerCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ import { spawn } from 'node:child_process';
import { existsSync, readFileSync } from 'node:fs';
import * as path from 'node:path';
import { CommandBase, type ICommandDaemon } from '@daemons/command-daemon/shared/CommandBase';
import type { JTAGContext } from '@system/core/types/JTAGTypes';
import type { CommandScope, JTAGContext } from '@system/core/types/JTAGTypes';
import { ValidationError } from '@system/core/types/ErrorTypes';
import type { AircSendParams, AircSendResult } from '../shared/AircSendTypes';
import { createAircSendResultFromParams } from '../shared/AircSendTypes';

export class AircSendServerCommand extends CommandBase<AircSendParams, AircSendResult> {
protected static override get naturalScope(): CommandScope {
return { type: 'room' };
}

constructor(context: JTAGContext, subpath: string, commander: ICommandDaemon) {
super('airc/send', context, subpath, commander);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export class DecisionProposeServerCommand extends DecisionProposeCommand {

const proposerId: UUID = params.userId;
const proposerName: string = proposerResult.data.displayName;
const scope = params.scope || 'all';
const scope = params.proposalScope || 'all';
const significanceLevel = params.significanceLevel || 'medium';
const proposalId = generateUUID();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface DecisionProposeParams extends CommandParams {
}>;

/** Who should vote on this? */
scope?: ProposalScope; // Default: 'all'
proposalScope?: ProposalScope; // Default: 'all'

/** How urgent is this? Determines response window */
significanceLevel?: SignificanceLevel; // Default: 'medium'
Expand Down Expand Up @@ -102,4 +102,3 @@ export const createCollaborationDecisionProposeResultFromParams = (
params: DecisionProposeParams,
differences: Omit<DecisionProposeResult, 'context' | 'sessionId' | 'userId'>
): DecisionProposeResult => transformPayload(params, differences);

6 changes: 5 additions & 1 deletion src/commands/grid/send/browser/GridSendBrowserCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
*/

import { CommandBase, type ICommandDaemon } from '@daemons/command-daemon/shared/CommandBase';
import type { JTAGContext } from '@system/core/types/JTAGTypes';
import type { CommandScope, JTAGContext } from '@system/core/types/JTAGTypes';
import type { GridSendParams, GridSendResult } from '../shared/GridSendTypes';

export class GridSendBrowserCommand extends CommandBase<GridSendParams, GridSendResult> {
protected static override get naturalScope(): CommandScope {
return { type: 'grid' };
}

constructor(context: JTAGContext, subpath: string, commander: ICommandDaemon) {
super('grid/send', context, subpath, commander);
}
Expand Down
6 changes: 5 additions & 1 deletion src/commands/grid/send/server/GridSendServerCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
*/

import { CommandBase, type ICommandDaemon } from '@daemons/command-daemon/shared/CommandBase';
import type { JTAGContext } from '@system/core/types/JTAGTypes';
import type { CommandScope, JTAGContext } from '@system/core/types/JTAGTypes';
import type { GridSendParams, GridSendResult } from '../shared/GridSendTypes';
import { RustCoreIPCClient, getContinuumCoreSocketPath } from '../../../../workers/continuum-core/bindings/RustCoreIPC';

export class GridSendServerCommand extends CommandBase<GridSendParams, GridSendResult> {
private rustClient: RustCoreIPCClient;

protected static override get naturalScope(): CommandScope {
return { type: 'grid' };
}

constructor(context: JTAGContext, subpath: string, commander: ICommandDaemon) {
super('grid/send', context, subpath, commander);
this.rustClient = new RustCoreIPCClient(getContinuumCoreSocketPath());
Expand Down
4 changes: 2 additions & 2 deletions src/commands/skill/list/server/SkillListServerCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export class SkillListServerCommand extends CommandBase<SkillListParams, SkillLi
if (params.status?.trim()) {
filter.status = params.status;
}
if (params.scope?.trim()) {
filter.scope = params.scope;
if (params.skillScope?.trim()) {
filter.scope = params.skillScope;
}
if (params.createdById?.trim()) {
filter.createdById = params.createdById;
Expand Down
10 changes: 5 additions & 5 deletions src/commands/skill/list/shared/SkillListTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import type { UUID } from '@system/core/types/CrossPlatformUUID';
export interface SkillListParams extends CommandParams {
// Filter by lifecycle status (proposed, approved, generated, validated, active, failed, deprecated)
status?: string;
// Filter by scope (personal, team)
scope?: string;
// Filter by skill visibility scope (personal, team)
skillScope?: string;
// Filter by creator persona ID
createdById?: string;
// Maximum results to return (default: 20)
Expand All @@ -34,8 +34,8 @@ export const createSkillListParams = (
data: {
// Filter by lifecycle status (proposed, approved, generated, validated, active, failed, deprecated)
status?: string;
// Filter by scope (personal, team)
scope?: string;
// Filter by skill visibility scope (personal, team)
skillScope?: string;
// Filter by creator persona ID
createdById?: string;
// Maximum results to return (default: 20)
Expand All @@ -44,7 +44,7 @@ export const createSkillListParams = (
): SkillListParams => createPayload(context, sessionId, {
userId: SYSTEM_SCOPES.SYSTEM,
status: data.status ?? '',
scope: data.scope ?? '',
skillScope: data.skillScope ?? '',
createdById: data.createdById ?? '',
limit: data.limit ?? 0,
...data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class SkillProposeServerCommand extends CommandBase<SkillProposeParams, S

async execute(params: SkillProposeParams): Promise<SkillProposeResult> {
const { name, description, implementation, personaId } = params;
const scope: SkillScope = (params.scope === 'team' ? 'team' : 'personal');
const scope: SkillScope = (params.skillScope === 'team' ? 'team' : 'personal');

if (!name?.trim()) {
throw new ValidationError('name', "Missing required parameter 'name'. Provide the command name (e.g., 'analysis/complexity').");
Expand Down Expand Up @@ -99,7 +99,7 @@ export class SkillProposeServerCommand extends CommandBase<SkillProposeParams, S
{ label: 'Request Changes', description: 'Suggest modifications before approval' },
{ label: 'Reject', description: 'Decline this skill proposal' },
],
scope: 'all',
proposalScope: 'all',
significanceLevel: 'medium',
context: proposeContext,
});
Expand Down
6 changes: 3 additions & 3 deletions src/commands/skill/propose/shared/SkillProposeTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface SkillProposeParams extends CommandParams {
// Natural language description of the implementation logic
implementation: string;
// Who can use it: 'personal' (default) or 'team' (requires approval)
scope?: string;
skillScope?: string;
// Usage examples array [{description, command, expectedResult?}]
examples?: Record<string, unknown>[];
// AI persona proposing this skill
Expand All @@ -51,15 +51,15 @@ export const createSkillProposeParams = (
// Natural language description of the implementation logic
implementation: string;
// Who can use it: 'personal' (default) or 'team' (requires approval)
scope?: string;
skillScope?: string;
// Usage examples array [{description, command, expectedResult?}]
examples?: Record<string, unknown>[];
// AI persona proposing this skill
personaId: string;
}
): SkillProposeParams => createPayload(context, sessionId, {
userId: SYSTEM_SCOPES.SYSTEM,
scope: data.scope ?? '',
skillScope: data.skillScope ?? '',
examples: data.examples ?? undefined,
...data
});
Expand Down
26 changes: 23 additions & 3 deletions src/daemons/command-daemon/shared/CommandBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { JTAGModule } from '../../../system/core/shared/JTAGModule';
import type { JTAGContext, CommandParams, CommandResult } from '../../../system/core/types/JTAGTypes';
import type { CommandScope, JTAGContext, CommandParams, CommandResult } from '../../../system/core/types/JTAGTypes';
import { JTAG_ENVIRONMENTS, JTAGMessageFactory } from '../../../system/core/types/JTAGTypes';
import { type UUID } from '../../../system/core/types/CrossPlatformUUID';
import { SYSTEM_SCOPES } from '../../../system/core/types/SystemScopes';
Expand Down Expand Up @@ -82,6 +82,17 @@ export abstract class CommandBase<TParams extends CommandParams = CommandParams,
return 'auto';
}

/**
* Natural execution scope for this command.
*
* Subclasses override this when a command is inherently room/project/grid
* scoped. Commands with no natural scope leave params.scope unset unless
* the caller provided one explicitly.
*/
protected static get naturalScope(): CommandScope | undefined {
return undefined;
}

/**
* Static execute - Universal command execution from anywhere
*
Expand Down Expand Up @@ -154,7 +165,16 @@ export abstract class CommandBase<TParams extends CommandParams = CommandParams,
* @param sessionId - Current session ID from the active request
*/
public getDefaultParams(sessionId: UUID, context: JTAGContext): TParams {
return {sessionId, context, userId: SYSTEM_SCOPES.SYSTEM} as TParams;
const commandClass = this.constructor as typeof CommandBase;
const params: CommandParams = {
sessionId,
context,
userId: SYSTEM_SCOPES.SYSTEM,
};
if (commandClass.naturalScope) {
return { ...params, scope: commandClass.naturalScope } as TParams;
}
return params as TParams;
}

/**
Expand Down Expand Up @@ -292,4 +312,4 @@ export abstract class CommandBase<TParams extends CommandParams = CommandParams,

return baseResult;
}
}
}
17 changes: 11 additions & 6 deletions src/daemons/command-daemon/shared/CommandDaemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,22 +142,28 @@ export abstract class CommandDaemon extends DaemonBase {
}

try {
// Check if timeout is specified in command params
const timeout = (message.payload as CommandParams).timeout;

// Resolve userId: use payload's userId if present and real, otherwise resolve from session
let resolvedUserId: UUID = (message.payload as CommandParams).userId ?? SYSTEM_SCOPES.SYSTEM;
if (resolvedUserId === SYSTEM_SCOPES.SYSTEM && requestSessionId) {
resolvedUserId = await this.resolveUserIdFromSession(requestSessionId) ?? SYSTEM_SCOPES.SYSTEM;
}

const scopedParams = command.withDefaults(
{ ...message.payload, userId: resolvedUserId } as Partial<CommandParams>,
requestSessionId,
requestContext,
);

// Check if timeout is specified in command params
const timeout = scopedParams.timeout;

// Grid routing: check if this command should execute on a remote node.
// Uses the same interceptor registered on Commands (server-side only).
// Skip for grid/* commands to avoid infinite recursion.
if (!commandName.startsWith('grid/')) {
const interceptor = (Commands as unknown as { _gridInterceptor: { tryRouteRemote: (cmd: string, params: unknown) => Promise<unknown> } | null })._gridInterceptor;
if (interceptor) {
const remoteResult = await interceptor.tryRouteRemote(commandName, message.payload);
const remoteResult = await interceptor.tryRouteRemote(commandName, scopedParams);
if (remoteResult !== null) {
return createCommandSuccessResponse(remoteResult as CommandResult, requestContext, undefined, requestSessionId);
}
Expand All @@ -166,7 +172,7 @@ export abstract class CommandDaemon extends DaemonBase {

// Execute command with session context for dual logging
const executionPromise = globalSessionContext.withSession(requestSessionId, async () => {
return await command.execute({ userId: resolvedUserId, ...message.payload } as CommandParams);
return await command.execute(scopedParams);
});

// Apply timeout if specified
Expand Down Expand Up @@ -302,4 +308,3 @@ export abstract class CommandDaemon extends DaemonBase {
});
}
}

12 changes: 12 additions & 0 deletions src/shared/generated/contracts/ContractAcceptedPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* `contract:accepted` — proposer's signed selection of one bidder.
*/
export type ContractAcceptedPayload = { contractId: string, proposerId: string, acceptedBidderId: string,
/**
* Hash of the accepted bid envelope — pins exactly which bid was
* taken (defense against bid-rewrite attacks where two bids share
* a contract_id).
*/
acceptedBidHash: string, };
16 changes: 16 additions & 0 deletions src/shared/generated/contracts/ContractBidPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* `contract:bid` — an executor's offer to take on a proposed contract.
*/
export type ContractBidPayload = { contractId: string, bidderId: string, bidAmount: bigint,
/**
* Bidder's promised SLA (max latency in ms). Proposer uses this
* in the bid-selection policy (lower latency + lower bid wins,
* per the policy engine).
*/
maxLatencyMs: number,
/**
* Bidder's expiry — how long this bid is honored if accepted.
*/
bidExpiryUnixMs: bigint, };
21 changes: 21 additions & 0 deletions src/shared/generated/contracts/ContractDeliveredPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* `contract:delivered` — executor's signed assertion that the work is
* done. Carries the alloy_hash of the actual artifact (which the
* proposer compares against the originally-proposed alloy_hash to
* detect bait-and-switch).
*/
export type ContractDeliveredPayload = { contractId: string, executorId: string,
/**
* Hash of the delivered artifact (may differ from the proposed
* alloy_hash if the executor produced a SPECIFIC output that
* satisfies the proposed CONTRACT).
*/
deliveredAlloyHash: string,
/**
* Optional location pointer (URL, IPFS CID, etc.) for fetching
* the artifact bytes. The hash is the canonical reference; this
* is convenience.
*/
artifactUrl?: string, };
12 changes: 12 additions & 0 deletions src/shared/generated/contracts/ContractDisputedPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* `contract:disputed` — any signer can file. Replay reproduces every
* disputed contract for auditor review.
*/
export type ContractDisputedPayload = { contractId: string, disputerId: string, reason: string,
/**
* Optional reference to the specific prior event being disputed
* (e.g. the verified-hash if the disputer claims wrong verdict).
*/
disputedEventHash?: string, };
8 changes: 8 additions & 0 deletions src/shared/generated/contracts/ContractExecutingPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* `contract:executing` — executor's signed "work started" beacon.
* Optional event (the chain stays valid without it) but used by the
* router daemon to mark a routing slot as in-use.
*/
export type ContractExecutingPayload = { contractId: string, executorId: string, startedAtUnixMs: bigint, };
13 changes: 13 additions & 0 deletions src/shared/generated/contracts/ContractPaidPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* `contract:paid` — payer's signed settlement record. For the
* zero-cost household tier this is still emitted (audit completeness)
* with `amount: 0`.
*/
export type ContractPaidPayload = { contractId: string, payerId: string, payeeId: string, amount: bigint, currency: string,
/**
* Optional settlement reference (chain tx hash, internal ledger
* entry id, etc.). Not load-bearing for replay; just provenance.
*/
settlementRef?: string, };
32 changes: 32 additions & 0 deletions src/shared/generated/contracts/ContractProposedPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

/**
* `contract:proposed` — initiator publishes a contract for bidding.
*
* `alloy_hash` references the substance of what's being contracted —
* matches the proof-contract layer in
* `docs/grid/FORGE-ALLOY-PROOF-CONTRACTS.md`. For pre-alloy use cases
* (e.g. a `ping` dispatch with no proof bundle) the hash references
* a synthetic "ping contract" alloy with no proof suite.
*/
export type ContractProposedPayload = { contractId: string, proposerId: string,
/**
* SHA-256 reference to the alloy bundle describing the work.
* Hex-encoded for human readability + ts-rs `string` mapping.
*/
alloyHash: string,
/**
* Currency/escrow terms. Zero-cost ("household") tier = empty
* `bid_currency` + zero `max_bid`.
*/
bidCurrency: string, maxBid: bigint,
/**
* Expiry (Unix ms). After this point the proposal is dead even
* if no `:accepted` was ever emitted.
*/
expiryUnixMs: bigint,
/**
* Required executor capability tag — matches the L1-4
* `presence:peer-manifest` capability index format.
*/
requiredCapability: string, };
Loading
Loading