Skip to content

Commit 655254a

Browse files
feat(protocol): reconcile SDK protocol with factory-mono-alpha (add commands/crons, retire loop RPCs) (#60)
* feat(protocol): reconcile SDK protocol with factory-mono-alpha Adds slash-command + cron schemas, retires the DaemonLoop RPC family per FAC-19606, bumps FACTORY_PROTOCOL_VERSION to 1.66.0, and aligns wire-level constants with mono. Version bumped 0.5.0 -> 0.6.0. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * feat(protocol): add ./protocol subpath export Adds a dedicated './protocol' subpath export so consumers can import the wire-protocol schemas directly without pulling the full SDK surface: import { daemon } from '@factory/droid-sdk/protocol'; Builds a separate dist/protocol/index.{js,cjs,d.ts,d.cts} via tsup. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * feat(protocol): reconcile schemas with factory-mono-alpha source of truth Adds missing fields/enum members detected by mono's verify-sdk-parity audit so the SDK is bit-equivalent to mono's wire schemas: - enums.ts: add ModelID entries ORIEL_0601, OXIDE_0601, OXBOW_0601, OCELOT_0601 (Olympus families released after the previous port). - general-settings.ts: add McpAutonomyUrlOverrideSchema + mcpAutonomyUrlOverrides on ManagedSettingsBaseSchema, and dismissedNewModels on GeneralSettingsSchema. - daemon/droid.ts: - DaemonGetGitDiffDataSchema: add committedDiff / committedFiles / committedTotalAdditions / committedTotalDeletions for the committed-only diff section the frontend renders. - DaemonGetGitDiffRequestParamsSchema: add statsOnly. - DaemonGetWorkspaceFileContentRequestParamsSchema: add encoding (utf8|base64) for binary file previews. - DaemonGetWorkspaceFileContentResultSchema: add encoding, mimeType, isBinary so the frontend can guard binary content properly. After this change factory-mono-alpha reports 265/265 schema MATCH and 0 MISMATCH against @factory/droid-sdk/protocol. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * chore(protocol): scrub internal references from public schemas Strips internal-architecture references from src/protocol/** so they no longer leak into the published bundles and source-maps: - Remove file headers referencing the internal monorepo and verbatim port provenance from ~30 protocol files; replace with neutral one-line descriptions where useful. - Scrub billing/architecture JSDoc on WorkerFailureReason and MissionPauseReason (the enum members are unchanged; only the descriptive comments around them are tightened). - Drop the editorial 'Deprecated' / 'Extra Usage (overage) billing tier' comments from LLMModelTier members. - Drop incidental references to internal infra (Vercel, Firestore sync, EAP cleanup, backend-v0-sessions, replay bug #974, MissionRunner / MissionFileService class names) from JSDoc and inline comments. - Add *.tgz to .gitignore so packed builds aren't accidentally committed. No schema, enum value, or exported symbol shape changes; bundle parity against mono is unaffected (still 265/265 MATCH). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --------- Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
1 parent 68f9d43 commit 655254a

37 files changed

Lines changed: 895 additions & 345 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ node_modules/
33

44
# Build output
55
dist/
6+
*.tgz
67

78
# Coverage
89
coverage/

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@factory/droid-sdk",
3-
"version": "0.5.0",
3+
"version": "0.6.0",
44
"private": false,
55
"description": "TypeScript SDK for the Factory Droid CLI",
66
"keywords": [
@@ -26,6 +26,16 @@
2626
"types": "./dist/index.d.cts",
2727
"default": "./dist/index.cjs"
2828
}
29+
},
30+
"./protocol": {
31+
"import": {
32+
"types": "./dist/protocol/index.d.ts",
33+
"default": "./dist/protocol/index.js"
34+
},
35+
"require": {
36+
"types": "./dist/protocol/index.d.cts",
37+
"default": "./dist/protocol/index.cjs"
38+
}
2939
}
3040
},
3141
"files": [

src/protocol/cli.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// Source-of-truth mirror of factory-mono-alpha CLI protocol schemas.
2-
// Verbatim copy of packages/common/src/droid/schemas/cli.ts.
3-
41
import { z } from 'zod';
52

63
import { SandboxModeSchema } from './custom-models.js';

src/protocol/client.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// Source-of-truth mirror of factory-mono-alpha client protocol schemas.
2-
// Verbatim copy of packages/common/src/droid/schemas/client.ts.
3-
41
import { z } from 'zod';
52

63
import {
@@ -689,6 +686,26 @@ export const ListSkillsRequestSchema = JsonRpcBaseRequestSchema.extend({
689686
params: ListSkillsRequestParamsSchema,
690687
});
691688

689+
// List commands request (returns all custom slash commands)
690+
const ListCommandsRequestParamsSchema = z.object({});
691+
692+
export const CustomCommandInfoSchema = z.object({
693+
name: z.string(),
694+
description: z.string(),
695+
argumentHint: z.string().optional(),
696+
// Whether the command is backed by an executable script (resolution runs it)
697+
isExecutable: z.boolean().optional(),
698+
});
699+
700+
const ListCommandsResultSchema = z.object({
701+
commands: z.array(CustomCommandInfoSchema),
702+
});
703+
704+
export const ListCommandsRequestSchema = JsonRpcBaseRequestSchema.extend({
705+
method: z.literal(DroidServerMethod.LIST_COMMANDS),
706+
params: ListCommandsRequestParamsSchema,
707+
});
708+
692709
const GetContextStatsRequestParamsSchema = z.object({});
693710

694711
export { ContextStatsSchema as GetContextStatsResultSchema };
@@ -917,6 +934,7 @@ export const ClientRequestSchema = z.discriminatedUnion('method', [
917934
ToggleMcpToolRequestSchema,
918935
SubmitMcpAuthCodeRequestSchema,
919936
ListSkillsRequestSchema,
937+
ListCommandsRequestSchema,
920938
GetContextStatsRequestSchema,
921939
GetContextBreakdownRequestSchema,
922940
SubmitBugReportRequestSchema,
@@ -1068,6 +1086,13 @@ export const ListSkillsResponseSchema = z.union([
10681086
JsonRpcBaseResponseFailureSchema,
10691087
]);
10701088

1089+
export const ListCommandsResponseSchema = z.union([
1090+
JsonRpcBaseResponseSuccessSchema.extend({
1091+
result: ListCommandsResultSchema,
1092+
}),
1093+
JsonRpcBaseResponseFailureSchema,
1094+
]);
1095+
10711096
export const GetContextStatsResponseSchema = z.union([
10721097
JsonRpcBaseResponseSuccessSchema.extend({
10731098
result: ContextStatsSchema,

src/protocol/constants.ts

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// Source-of-truth mirror of factory-mono-alpha protocol constants.
2-
// Faithful copy of:
3-
// packages/common/src/droid/schemas/constants.ts
4-
// packages/common/src/droid/constants.ts (LOOP_INTERVAL_POLICY)
5-
// Keep shapes/values identical to the private monorepo to avoid protocol drift.
1+
import { DroidWorkingState } from './enums.js';
2+
3+
export const FACTORY_CLIENT_HEADER = 'X-Factory-Client';
4+
export const FACTORY_CLIENT_VERSION = 'X-Client-Version';
5+
export const ACTIVE_ORGANIZATION_HEADER = 'X-Factory-Org-Id';
66

77
/**
88
* Legacy envelope field for old JSON-RPC peers - `factoryApiVersion` must be set to this value.
@@ -11,39 +11,60 @@
1111
*/
1212
export const LEGACY_FACTORY_API_VERSION = '1.0.0' as const;
1313

14-
export const FACTORY_PROTOCOL_VERSION = '1.62.0' as const;
14+
export const FACTORY_PROTOCOL_VERSION = '1.66.0' as const;
1515

1616
export const JSONRPC_VERSION = '2.0' as const;
1717

1818
/**
19-
* Sentinel ModelID value for the Factory routing model. Faithful copy of
20-
* packages/common/src/llm/constants.ts.
19+
* Sentinel ModelID value for the Factory routing model.
2120
*/
2221
export const FACTORY_ROUTER_MODEL_ID = 'factory-router' as const;
2322

2423
/**
2524
* Sentinel value used by CompactionModelSchema to mean "use the session's
26-
* current model for compaction". Faithful copy of
27-
* packages/common/src/settings/constants.ts.
25+
* current model for compaction".
2826
*/
2927
export const CURRENT_COMPACTION_MODEL = 'current-model';
3028

31-
// Faithful copy of packages/common/src/settings/constants.ts router-rule
32-
// guardrails. Used by ManagedSettingsBaseSchema and FactoryRouterRuleSchema.
33-
3429
/** Sized comparably to a trimmed user message in the classifier context budget. */
3530
export const FACTORY_ROUTER_GUIDANCE_MAX_LENGTH = 2000;
3631
export const FACTORY_ROUTER_RULES_MAX_COUNT = 20;
3732
export const FACTORY_ROUTER_RULE_WHEN_MAX_LENGTH = 300;
3833
export const FACTORY_ROUTER_RULE_GUIDANCE_MAX_LENGTH = 600;
3934

35+
/**
36+
* System reminder tag constants used for marking content as hidden from users.
37+
*/
38+
export const SYSTEM_REMINDER_START = '<system-reminder>';
39+
export const SYSTEM_REMINDER_END = '</system-reminder>';
40+
41+
/**
42+
* System notification tag constants used for marking notifications as hidden from users.
43+
*/
44+
export const SYSTEM_NOTIFICATION_START = '<system-notification>';
45+
export const SYSTEM_NOTIFICATION_END = '</system-notification>';
46+
47+
export const EXIT_SPEC_MODE_REJECTED_MESSAGE =
48+
'Plan not approved - remaining in Spec Mode. Provide feedback to refine the spec.';
49+
4050
const seconds = (value: number) => value * 1_000;
4151
const minutes = (value: number) => seconds(value * 60);
4252
const hours = (value: number) => minutes(value * 60);
4353

4454
export const LOOP_INTERVAL_POLICY = {
45-
minMs: seconds(5),
55+
minMs: minutes(1),
4656
maxMs: hours(24),
47-
displayRange: '5s–24h',
48-
examples: '5s, 5m, 30m, 2h',
57+
displayRange: '1m–24h',
58+
examples: '5m, 30m, 2h',
4959
} as const;
60+
61+
const DROID_RUNNING_STATES = [
62+
DroidWorkingState.Thinking,
63+
DroidWorkingState.StreamingAssistantMessage,
64+
DroidWorkingState.ExecutingTool,
65+
DroidWorkingState.CompactingConversation,
66+
];
67+
export const DROID_IN_PROGRESS_STATES = [
68+
...DROID_RUNNING_STATES,
69+
DroidWorkingState.WaitingForToolConfirmation,
70+
];

src/protocol/crons.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { z } from 'zod';
2+
3+
const CronExpressionSchema = z
4+
.string()
5+
.trim()
6+
.regex(/^(\S+\s+){4}\S+$/, 'Expected a standard 5-field cron expression');
7+
8+
export const CronCreateToolInputSchema = z.object({
9+
expression: CronExpressionSchema.describe(
10+
'Standard 5-field cron expression in local time.'
11+
),
12+
job: z.object({
13+
type: z.literal('prompt'),
14+
prompt: z.string().trim().min(1),
15+
}),
16+
target: z
17+
.object({
18+
type: z.literal('same_session'),
19+
})
20+
.optional(),
21+
recurring: z.boolean().describe('true for recurring tasks, false for once'),
22+
});
23+
24+
export const CronDeleteToolInputSchema = z.object({
25+
cronId: z.string().length(8),
26+
});
27+
28+
export const CronListToolInputSchema = z.object({});

src/protocol/custom-models.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
// Source-of-truth mirror of factory-mono-alpha custom-model schemas (symbol-only).
2-
// Verbatim copy of CustomModelBedrockSchema, ManagedCustomModelSchema, and
3-
// CustomModelsSchema from packages/common/src/settings/schema.ts. Ported as-is
4-
// per the no-modification rule (includes apiKey / aws credential fields).
5-
// SandboxModeSchema is colocated here (one-liner from the same settings module).
1+
// Custom-model schemas (includes apiKey / aws credential fields).
2+
// SandboxModeSchema is colocated here.
63

74
import { z } from 'zod';
85

src/protocol/daemon/automations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ export const DaemonListAutomationsRequestSchema =
1616
});
1717

1818
export const AutomationEntrySchema = z.object({
19-
/** Directory name slug (e.g. "health-check"). Kept as `id` because protocol rules forbid renaming required fields. */
19+
/** Directory name slug (e.g. "health-check"). */
2020
id: z.string(),
21-
/** Stable UUID from HEARTBEAT.md frontmatter, used for backend/Firestore sync. */
21+
/** Stable UUID for backend sync. */
2222
uuid: z.string().optional(),
2323
name: z.string(),
2424
description: z.string().optional(),

src/protocol/daemon/commands.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { z } from 'zod';
2+
3+
import { CustomCommandInfoSchema } from '../client.js';
4+
import { JsonRpcBaseRequestSchema } from '../json-rpc.js';
5+
import { DaemonDroidMethod } from './enums.js';
6+
7+
// LIST_COMMANDS - get all custom slash commands for a session
8+
const DaemonListCommandsRequestParamsSchema = z.object({
9+
sessionId: z.string(),
10+
});
11+
12+
export const DaemonListCommandsRequestSchema = JsonRpcBaseRequestSchema.extend({
13+
method: z.literal(DaemonDroidMethod.LIST_COMMANDS),
14+
params: DaemonListCommandsRequestParamsSchema,
15+
});
16+
17+
export const DaemonListCommandsResultSchema = z.object({
18+
commands: z.array(CustomCommandInfoSchema),
19+
});

0 commit comments

Comments
 (0)