@nghyane/arcane 0.1.8 → 0.1.11

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.
Files changed (131) hide show
  1. package/package.json +6 -6
  2. package/src/config/settings-schema.ts +0 -10
  3. package/src/discovery/helpers.ts +1 -6
  4. package/src/index.ts +1 -0
  5. package/src/main.ts +3 -0
  6. package/src/memories/index.ts +3 -3
  7. package/src/modes/components/model-selector.ts +1 -1
  8. package/src/modes/components/settings-defs.ts +0 -8
  9. package/src/modes/components/status-line.ts +15 -40
  10. package/src/modes/components/user-message.ts +2 -0
  11. package/src/modes/components/welcome.ts +1 -1
  12. package/src/modes/interactive-mode.ts +2 -0
  13. package/src/modes/theme/dark.json +56 -59
  14. package/src/modes/theme/defaults/dark-catppuccin.json +47 -56
  15. package/src/modes/theme/defaults/dark-dracula.json +24 -32
  16. package/src/modes/theme/defaults/dark-gruvbox.json +53 -74
  17. package/src/modes/theme/defaults/dark-solarized.json +33 -35
  18. package/src/modes/theme/defaults/dark-tokyo-night.json +57 -67
  19. package/src/modes/theme/defaults/index.ts +3 -179
  20. package/src/modes/theme/defaults/light-catppuccin.json +42 -50
  21. package/src/modes/theme/defaults/light-github.json +68 -94
  22. package/src/modes/theme/defaults/light-solarized.json +41 -49
  23. package/src/modes/theme/light.json +14 -12
  24. package/src/modes/theme/theme-schema.json +4 -0
  25. package/src/modes/theme/theme.ts +89 -6
  26. package/src/patch/applicator.ts +12 -4
  27. package/src/prompts/agents/task.md +1 -1
  28. package/src/prompts/system/subagent-system-prompt.md +2 -14
  29. package/src/prompts/system/system-prompt.md +12 -14
  30. package/src/prompts/tools/task.md +49 -178
  31. package/src/prompts/tools/todo-write.md +4 -4
  32. package/src/sdk.ts +15 -16
  33. package/src/session/session-manager.ts +1 -3
  34. package/src/task/executor.ts +2 -2
  35. package/src/task/index.ts +5 -5
  36. package/src/task/types.ts +7 -20
  37. package/src/tools/index.ts +16 -33
  38. package/src/tools/subagent-tool.ts +5 -5
  39. package/src/tools/todo-write.ts +0 -37
  40. package/src/tui/output-block.ts +2 -12
  41. package/src/modes/theme/defaults/alabaster.json +0 -93
  42. package/src/modes/theme/defaults/amethyst.json +0 -96
  43. package/src/modes/theme/defaults/anthracite.json +0 -93
  44. package/src/modes/theme/defaults/basalt.json +0 -91
  45. package/src/modes/theme/defaults/birch.json +0 -95
  46. package/src/modes/theme/defaults/dark-abyss.json +0 -91
  47. package/src/modes/theme/defaults/dark-arctic.json +0 -104
  48. package/src/modes/theme/defaults/dark-aurora.json +0 -95
  49. package/src/modes/theme/defaults/dark-cavern.json +0 -91
  50. package/src/modes/theme/defaults/dark-copper.json +0 -95
  51. package/src/modes/theme/defaults/dark-cosmos.json +0 -90
  52. package/src/modes/theme/defaults/dark-cyberpunk.json +0 -102
  53. package/src/modes/theme/defaults/dark-eclipse.json +0 -91
  54. package/src/modes/theme/defaults/dark-ember.json +0 -95
  55. package/src/modes/theme/defaults/dark-equinox.json +0 -90
  56. package/src/modes/theme/defaults/dark-forest.json +0 -96
  57. package/src/modes/theme/defaults/dark-github.json +0 -105
  58. package/src/modes/theme/defaults/dark-lavender.json +0 -95
  59. package/src/modes/theme/defaults/dark-lunar.json +0 -89
  60. package/src/modes/theme/defaults/dark-midnight.json +0 -95
  61. package/src/modes/theme/defaults/dark-monochrome.json +0 -94
  62. package/src/modes/theme/defaults/dark-monokai.json +0 -98
  63. package/src/modes/theme/defaults/dark-nebula.json +0 -90
  64. package/src/modes/theme/defaults/dark-nord.json +0 -97
  65. package/src/modes/theme/defaults/dark-ocean.json +0 -101
  66. package/src/modes/theme/defaults/dark-one.json +0 -100
  67. package/src/modes/theme/defaults/dark-rainforest.json +0 -91
  68. package/src/modes/theme/defaults/dark-reef.json +0 -91
  69. package/src/modes/theme/defaults/dark-retro.json +0 -92
  70. package/src/modes/theme/defaults/dark-rose-pine.json +0 -96
  71. package/src/modes/theme/defaults/dark-sakura.json +0 -95
  72. package/src/modes/theme/defaults/dark-slate.json +0 -95
  73. package/src/modes/theme/defaults/dark-solstice.json +0 -90
  74. package/src/modes/theme/defaults/dark-starfall.json +0 -91
  75. package/src/modes/theme/defaults/dark-sunset.json +0 -99
  76. package/src/modes/theme/defaults/dark-swamp.json +0 -90
  77. package/src/modes/theme/defaults/dark-synthwave.json +0 -103
  78. package/src/modes/theme/defaults/dark-taiga.json +0 -91
  79. package/src/modes/theme/defaults/dark-terminal.json +0 -95
  80. package/src/modes/theme/defaults/dark-tundra.json +0 -91
  81. package/src/modes/theme/defaults/dark-twilight.json +0 -91
  82. package/src/modes/theme/defaults/dark-volcanic.json +0 -91
  83. package/src/modes/theme/defaults/graphite.json +0 -92
  84. package/src/modes/theme/defaults/light-arctic.json +0 -107
  85. package/src/modes/theme/defaults/light-aurora-day.json +0 -91
  86. package/src/modes/theme/defaults/light-canyon.json +0 -91
  87. package/src/modes/theme/defaults/light-cirrus.json +0 -90
  88. package/src/modes/theme/defaults/light-coral.json +0 -95
  89. package/src/modes/theme/defaults/light-cyberpunk.json +0 -96
  90. package/src/modes/theme/defaults/light-dawn.json +0 -90
  91. package/src/modes/theme/defaults/light-dunes.json +0 -91
  92. package/src/modes/theme/defaults/light-eucalyptus.json +0 -95
  93. package/src/modes/theme/defaults/light-forest.json +0 -100
  94. package/src/modes/theme/defaults/light-frost.json +0 -95
  95. package/src/modes/theme/defaults/light-glacier.json +0 -91
  96. package/src/modes/theme/defaults/light-gruvbox.json +0 -108
  97. package/src/modes/theme/defaults/light-haze.json +0 -90
  98. package/src/modes/theme/defaults/light-honeycomb.json +0 -95
  99. package/src/modes/theme/defaults/light-lagoon.json +0 -91
  100. package/src/modes/theme/defaults/light-lavender.json +0 -95
  101. package/src/modes/theme/defaults/light-meadow.json +0 -91
  102. package/src/modes/theme/defaults/light-mint.json +0 -95
  103. package/src/modes/theme/defaults/light-monochrome.json +0 -101
  104. package/src/modes/theme/defaults/light-ocean.json +0 -99
  105. package/src/modes/theme/defaults/light-one.json +0 -99
  106. package/src/modes/theme/defaults/light-opal.json +0 -91
  107. package/src/modes/theme/defaults/light-orchard.json +0 -91
  108. package/src/modes/theme/defaults/light-paper.json +0 -95
  109. package/src/modes/theme/defaults/light-prism.json +0 -90
  110. package/src/modes/theme/defaults/light-retro.json +0 -98
  111. package/src/modes/theme/defaults/light-sand.json +0 -95
  112. package/src/modes/theme/defaults/light-savanna.json +0 -91
  113. package/src/modes/theme/defaults/light-soleil.json +0 -90
  114. package/src/modes/theme/defaults/light-sunset.json +0 -99
  115. package/src/modes/theme/defaults/light-synthwave.json +0 -98
  116. package/src/modes/theme/defaults/light-tokyo-night.json +0 -111
  117. package/src/modes/theme/defaults/light-wetland.json +0 -91
  118. package/src/modes/theme/defaults/light-zenith.json +0 -89
  119. package/src/modes/theme/defaults/limestone.json +0 -94
  120. package/src/modes/theme/defaults/mahogany.json +0 -97
  121. package/src/modes/theme/defaults/marble.json +0 -93
  122. package/src/modes/theme/defaults/obsidian.json +0 -91
  123. package/src/modes/theme/defaults/onyx.json +0 -91
  124. package/src/modes/theme/defaults/pearl.json +0 -93
  125. package/src/modes/theme/defaults/porcelain.json +0 -91
  126. package/src/modes/theme/defaults/quartz.json +0 -96
  127. package/src/modes/theme/defaults/sandstone.json +0 -95
  128. package/src/modes/theme/defaults/titanium.json +0 -90
  129. package/src/prompts/system/subagent-submit-reminder.md +0 -11
  130. package/src/tools/jtd-to-json-schema.ts +0 -247
  131. package/src/tools/submit-result.ts +0 -152
@@ -1,247 +0,0 @@
1
- /**
2
- * Convert JSON Type Definition (JTD) to JSON Schema.
3
- *
4
- * JTD (RFC 8927) is a simpler schema format. This converter allows users to
5
- * write schemas in JTD and have them converted to JSON Schema for model APIs.
6
- *
7
- * @see https://jsontypedef.com/
8
- * @see https://datatracker.ietf.org/doc/html/rfc8927
9
- */
10
-
11
- type JTDPrimitive =
12
- | "boolean"
13
- | "string"
14
- | "timestamp"
15
- | "float32"
16
- | "float64"
17
- | "int8"
18
- | "uint8"
19
- | "int16"
20
- | "uint16"
21
- | "int32"
22
- | "uint32";
23
-
24
- interface JTDType {
25
- type: JTDPrimitive;
26
- }
27
-
28
- interface JTDEnum {
29
- enum: string[];
30
- }
31
-
32
- interface JTDElements {
33
- elements: JTDSchema;
34
- }
35
-
36
- interface JTDValues {
37
- values: JTDSchema;
38
- }
39
-
40
- interface JTDProperties {
41
- properties?: Record<string, JTDSchema>;
42
- optionalProperties?: Record<string, JTDSchema>;
43
- }
44
-
45
- interface JTDDiscriminator {
46
- discriminator: string;
47
- mapping: Record<string, JTDProperties>;
48
- }
49
-
50
- interface JTDRef {
51
- ref: string;
52
- }
53
-
54
- interface JTDEmpty {}
55
-
56
- type JTDSchema = JTDType | JTDEnum | JTDElements | JTDValues | JTDProperties | JTDDiscriminator | JTDRef | JTDEmpty;
57
-
58
- const primitiveMap: Record<JTDPrimitive, string> = {
59
- boolean: "boolean",
60
- string: "string",
61
- timestamp: "string", // ISO 8601
62
- float32: "number",
63
- float64: "number",
64
- int8: "integer",
65
- uint8: "integer",
66
- int16: "integer",
67
- uint16: "integer",
68
- int32: "integer",
69
- uint32: "integer",
70
- };
71
-
72
- function isJTDType(schema: unknown): schema is JTDType {
73
- return typeof schema === "object" && schema !== null && "type" in schema;
74
- }
75
-
76
- function isJTDEnum(schema: unknown): schema is JTDEnum {
77
- return typeof schema === "object" && schema !== null && "enum" in schema;
78
- }
79
-
80
- function isJTDElements(schema: unknown): schema is JTDElements {
81
- return typeof schema === "object" && schema !== null && "elements" in schema;
82
- }
83
-
84
- function isJTDValues(schema: unknown): schema is JTDValues {
85
- return typeof schema === "object" && schema !== null && "values" in schema;
86
- }
87
-
88
- function isJTDProperties(schema: unknown): schema is JTDProperties {
89
- return typeof schema === "object" && schema !== null && ("properties" in schema || "optionalProperties" in schema);
90
- }
91
-
92
- function isJTDDiscriminator(schema: unknown): schema is JTDDiscriminator {
93
- return typeof schema === "object" && schema !== null && "discriminator" in schema;
94
- }
95
-
96
- function isJTDRef(schema: unknown): schema is JTDRef {
97
- return typeof schema === "object" && schema !== null && "ref" in schema;
98
- }
99
-
100
- function convertSchema(schema: unknown): unknown {
101
- if (schema === null || typeof schema !== "object") {
102
- return {};
103
- }
104
-
105
- // Type form: { type: "string" } → { type: "string" }
106
- if (isJTDType(schema)) {
107
- const jsonType = primitiveMap[schema.type as JTDPrimitive];
108
- if (!jsonType) {
109
- return { type: schema.type };
110
- }
111
- return { type: jsonType };
112
- }
113
-
114
- // Enum form: { enum: ["a", "b"] } → { enum: ["a", "b"] }
115
- if (isJTDEnum(schema)) {
116
- return { enum: schema.enum };
117
- }
118
-
119
- // Elements form: { elements: { type: "string" } } → { type: "array", items: ... }
120
- if (isJTDElements(schema)) {
121
- return {
122
- type: "array",
123
- items: convertSchema(schema.elements),
124
- };
125
- }
126
-
127
- // Values form: { values: { type: "string" } } → { type: "object", additionalProperties: ... }
128
- if (isJTDValues(schema)) {
129
- return {
130
- type: "object",
131
- additionalProperties: convertSchema(schema.values),
132
- };
133
- }
134
-
135
- // Properties form: { properties: {...}, optionalProperties: {...} }
136
- if (isJTDProperties(schema)) {
137
- const properties: Record<string, unknown> = {};
138
- const required: string[] = [];
139
-
140
- // Required properties
141
- if (schema.properties) {
142
- for (const [key, value] of Object.entries(schema.properties)) {
143
- properties[key] = convertSchema(value);
144
- required.push(key);
145
- }
146
- }
147
-
148
- // Optional properties
149
- if (schema.optionalProperties) {
150
- for (const [key, value] of Object.entries(schema.optionalProperties)) {
151
- properties[key] = convertSchema(value);
152
- }
153
- }
154
-
155
- const result: Record<string, unknown> = {
156
- type: "object",
157
- properties,
158
- additionalProperties: false,
159
- };
160
-
161
- if (required.length > 0) {
162
- result.required = required;
163
- }
164
-
165
- return result;
166
- }
167
-
168
- // Discriminator form: { discriminator: "type", mapping: { ... } }
169
- if (isJTDDiscriminator(schema)) {
170
- const oneOf: unknown[] = [];
171
-
172
- for (const [tag, props] of Object.entries(schema.mapping)) {
173
- const converted = convertSchema(props) as Record<string, unknown>;
174
- // Add the discriminator property
175
- const properties = (converted.properties || {}) as Record<string, unknown>;
176
- properties[schema.discriminator] = { const: tag };
177
-
178
- const required = ((converted.required as string[]) || []).slice();
179
- if (!required.includes(schema.discriminator)) {
180
- required.push(schema.discriminator);
181
- }
182
-
183
- oneOf.push({
184
- ...converted,
185
- properties,
186
- required,
187
- });
188
- }
189
-
190
- return { oneOf };
191
- }
192
-
193
- // Ref form: { ref: "MyType" } → { $ref: "#/$defs/MyType" }
194
- if (isJTDRef(schema)) {
195
- return { $ref: `#/$defs/${schema.ref}` };
196
- }
197
-
198
- // Empty form: {} → {} (accepts anything)
199
- return {};
200
- }
201
-
202
- /**
203
- * Detect if a schema is JTD format (vs JSON Schema).
204
- *
205
- * JTD schemas use: type (primitives), properties, optionalProperties, elements, values, enum, discriminator, ref
206
- * JSON Schema uses: type: "object", type: "array", items, additionalProperties, etc.
207
- */
208
- export function isJTDSchema(schema: unknown): boolean {
209
- if (schema === null || typeof schema !== "object") {
210
- return false;
211
- }
212
-
213
- const obj = schema as Record<string, unknown>;
214
-
215
- // JTD-specific keywords
216
- if ("elements" in obj) return true;
217
- if ("values" in obj) return true;
218
- if ("optionalProperties" in obj) return true;
219
- if ("discriminator" in obj) return true;
220
- if ("ref" in obj) return true;
221
-
222
- // JTD type primitives (JSON Schema doesn't have int32, float64, etc.)
223
- if ("type" in obj) {
224
- const jtdPrimitives = ["timestamp", "float32", "float64", "int8", "uint8", "int16", "uint16", "int32", "uint32"];
225
- if (jtdPrimitives.includes(obj.type as string)) {
226
- return true;
227
- }
228
- }
229
-
230
- // JTD properties form without type: "object" (JSON Schema requires it)
231
- if ("properties" in obj && !("type" in obj)) {
232
- return true;
233
- }
234
-
235
- return false;
236
- }
237
-
238
- /**
239
- * Convert JTD schema to JSON Schema.
240
- * If already JSON Schema, returns as-is.
241
- */
242
- export function jtdToJsonSchema(schema: unknown): unknown {
243
- if (!isJTDSchema(schema)) {
244
- return schema;
245
- }
246
- return convertSchema(schema);
247
- }
@@ -1,152 +0,0 @@
1
- /**
2
- * Submit result tool for structured subagent output.
3
- *
4
- * Subagents must call this tool to finish and return structured JSON output.
5
- */
6
- import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@nghyane/arcane-agent";
7
- import { StringEnum } from "@nghyane/arcane-ai";
8
- import type { Static, TObject } from "@sinclair/typebox";
9
- import { Type } from "@sinclair/typebox";
10
- import Ajv, { type ErrorObject, type ValidateFunction } from "ajv";
11
- import { subprocessToolRegistry } from "../task/subprocess-tool-registry";
12
- import type { ToolSession } from ".";
13
- import { jtdToJsonSchema } from "./jtd-to-json-schema";
14
-
15
- export interface SubmitResultDetails {
16
- data: unknown;
17
- status: "success" | "aborted";
18
- error?: string;
19
- }
20
-
21
- const ajv = new Ajv({ allErrors: true, strict: false });
22
-
23
- function normalizeSchema(schema: unknown): { normalized?: unknown; error?: string } {
24
- if (schema === undefined || schema === null) return {};
25
- if (typeof schema === "string") {
26
- try {
27
- return { normalized: JSON.parse(schema) };
28
- } catch (err) {
29
- return { error: err instanceof Error ? err.message : String(err) };
30
- }
31
- }
32
- return { normalized: schema };
33
- }
34
-
35
- function formatSchema(schema: unknown): string {
36
- if (schema === undefined) return "No schema provided.";
37
- if (typeof schema === "string") return schema;
38
- try {
39
- return JSON.stringify(schema, null, 2);
40
- } catch {
41
- return "[unserializable schema]";
42
- }
43
- }
44
-
45
- function formatAjvErrors(errors: ErrorObject[] | null | undefined): string {
46
- if (!errors || errors.length === 0) return "Unknown schema validation error.";
47
- return errors
48
- .map(err => {
49
- const path = err.instancePath ? `${err.instancePath}: ` : "";
50
- return `${path}${err.message ?? "invalid"}`;
51
- })
52
- .join("; ");
53
- }
54
-
55
- export class SubmitResultTool implements AgentTool<TObject, SubmitResultDetails> {
56
- readonly name = "submit_result";
57
- readonly label = "Submit Result";
58
- readonly description =
59
- "Finish the task with structured JSON output. Call exactly once at the end of the task.\n\n" +
60
- "If you cannot complete the task, call with status='aborted' and an error message.";
61
- readonly parameters: TObject;
62
-
63
- readonly #validate?: ValidateFunction;
64
- readonly #schemaError?: string;
65
-
66
- constructor(session: ToolSession) {
67
- const schemaResult = normalizeSchema(session.outputSchema);
68
- // Convert JTD to JSON Schema if needed (auto-detected)
69
- const normalizedSchema =
70
- schemaResult.normalized !== undefined ? jtdToJsonSchema(schemaResult.normalized) : undefined;
71
- let schemaError = schemaResult.error;
72
-
73
- if (normalizedSchema !== undefined && !schemaError) {
74
- try {
75
- this.#validate = ajv.compile(normalizedSchema as any);
76
- } catch (err) {
77
- schemaError = err instanceof Error ? err.message : String(err);
78
- }
79
- }
80
-
81
- this.#schemaError = schemaError;
82
-
83
- const schemaHint = formatSchema(normalizedSchema ?? session.outputSchema);
84
-
85
- // Use actual schema if provided, otherwise fall back to Type.Any
86
- // Merge description into the JSON schema for better tool documentation
87
- const dataSchema = normalizedSchema
88
- ? Type.Unsafe({
89
- ...(normalizedSchema as object),
90
- description: `Structured output matching the schema:\n${schemaHint}`,
91
- })
92
- : Type.Any({ description: "Structured JSON output (no schema specified)" });
93
-
94
- this.parameters = Type.Object({
95
- data: Type.Optional(dataSchema),
96
- status: Type.Optional(
97
- StringEnum(["success", "aborted"], {
98
- description: "Use 'aborted' if the task cannot be completed, defaults to 'success'",
99
- }),
100
- ),
101
- error: Type.Optional(Type.String({ description: "Error message when status is 'aborted'" })),
102
- });
103
- }
104
-
105
- async execute(
106
- _toolCallId: string,
107
- params: Static<TObject>,
108
- _signal?: AbortSignal,
109
- _onUpdate?: AgentToolUpdateCallback<SubmitResultDetails>,
110
- _context?: AgentToolContext,
111
- ): Promise<AgentToolResult<SubmitResultDetails>> {
112
- const status = (params.status ?? "success") as "success" | "aborted";
113
-
114
- // Skip validation when aborting - data is optional for aborts
115
- if (status === "success") {
116
- if (params.data === undefined || params.data === null) {
117
- throw new Error("data is required when status is 'success' (got null/undefined)");
118
- }
119
- if (this.#schemaError) {
120
- throw new Error(`Invalid output schema: ${this.#schemaError}`);
121
- }
122
- if (this.#validate && !this.#validate(params.data)) {
123
- throw new Error(`Output does not match schema: ${formatAjvErrors(this.#validate.errors)}`);
124
- }
125
- }
126
-
127
- const responseText =
128
- status === "aborted" ? `Task aborted: ${params.error || "No reason provided"}` : "Result submitted.";
129
-
130
- return {
131
- content: [{ type: "text", text: responseText }],
132
- details: { data: params.data, status, error: params.error as string | undefined },
133
- };
134
- }
135
- }
136
-
137
- // Register subprocess tool handler for extraction + termination.
138
- subprocessToolRegistry.register<SubmitResultDetails>("submit_result", {
139
- extractData: event => {
140
- const details = event.result?.details;
141
- if (!details || typeof details !== "object") return undefined;
142
- const record = details as Record<string, unknown>;
143
- const status = record.status;
144
- if (status !== "success" && status !== "aborted") return undefined;
145
- return {
146
- data: record.data,
147
- status,
148
- error: typeof record.error === "string" ? record.error : undefined,
149
- };
150
- },
151
- shouldTerminate: event => !event.isError,
152
- });