@gajae-code/coding-agent 0.13.2 → 0.13.3
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/CHANGELOG.md +33 -8
- package/dist/types/config/model-registry.d.ts +1 -0
- package/dist/types/config/settings-schema.d.ts +3 -3
- package/dist/types/main.d.ts +1 -0
- package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
- package/dist/types/modes/components/gajae-pet-widget.d.ts +5 -5
- package/dist/types/modes/components/pet-capability.d.ts +5 -5
- package/dist/types/modes/components/settings-selector.d.ts +5 -0
- package/dist/types/modes/theme/defaults/index.d.ts +118 -0
- package/dist/types/session/session-manager.d.ts +7 -0
- package/dist/types/tools/image-gen.d.ts +1 -0
- package/package.json +8 -8
- package/src/config/model-profile-activation.ts +3 -1
- package/src/config/model-profiles.ts +59 -2
- package/src/config/model-registry.ts +16 -1
- package/src/config/settings-schema.ts +1 -1
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
- package/src/internal-urls/docs-index.generated.ts +3 -2
- package/src/main.ts +4 -0
- package/src/modes/components/chrome.ts +4 -3
- package/src/modes/components/dynamic-theme-text.ts +22 -0
- package/src/modes/components/gajae-pet-widget.ts +130 -42
- package/src/modes/components/model-selector.ts +1 -6
- package/src/modes/components/pet-capability.ts +10 -5
- package/src/modes/components/settings-selector.ts +20 -5
- package/src/modes/components/status-line/segments.ts +3 -3
- package/src/modes/controllers/selector-controller.ts +61 -5
- package/src/modes/theme/defaults/index.ts +2 -0
- package/src/modes/theme/defaults/ouroboros.json +118 -0
- package/src/session/agent-session.ts +39 -0
- package/src/session/internal/managed-session-storage.ts +26 -19
- package/src/session/session-manager.ts +28 -0
- package/src/slash-commands/builtin-registry.ts +19 -3
- package/src/tools/image-gen.ts +322 -126
- package/src/tools/todo-contract.ts +55 -3
- package/src/tools/todo-write.ts +4 -3
|
@@ -50,6 +50,8 @@ const TODO_OP_KEYS = new Set(["op", "list", "task", "phase", "items", "text"]);
|
|
|
50
50
|
const TODO_INIT_ENTRY_KEYS = new Set(["phase", "items"]);
|
|
51
51
|
/** `content` is accepted only as a synonym the schema rewrites to `task`. */
|
|
52
52
|
const TODO_OP_KEYS_WITH_ALIASES = new Set([...TODO_OP_KEYS, "content"]);
|
|
53
|
+
const MAX_REJECTED_KEYS = 8;
|
|
54
|
+
const POSITIONAL_HANDLE_KEYS = new Set(["id", "ids", "index", "taskId", "task_id"]);
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
57
|
* Exact key corrections. `note` is the one repeatable confusion: it is an `op`
|
|
@@ -60,11 +62,27 @@ const TODO_OP_KEYS_WITH_ALIASES = new Set([...TODO_OP_KEYS, "content"]);
|
|
|
60
62
|
* an entry here when the replacement is unambiguous — never from fuzzy or
|
|
61
63
|
* edit-distance matching, because a wrong suggestion costs more turns than no
|
|
62
64
|
* suggestion.
|
|
65
|
+
*
|
|
66
|
+
* The positional-handle family (`id`, `index`, and spellings of them) is the
|
|
67
|
+
* other repeatable confusion: the tool result renders tasks as a list, so a
|
|
68
|
+
* caller assumes the list is addressable by ordinal. No op has ever taken a
|
|
69
|
+
* handle - a task is addressed by its verbatim content - and the executor
|
|
70
|
+
* already says so, but on the validated model-facing path this validator
|
|
71
|
+
* rejects the key first, so that message never gets its turn. One shared
|
|
72
|
+
* correction keeps both layers telling the same story.
|
|
63
73
|
*/
|
|
74
|
+
const POSITIONAL_HANDLE_CORRECTION =
|
|
75
|
+
'tasks have no id or index; target a task with "task" set to its exact content, or a whole phase with "phase"';
|
|
76
|
+
|
|
64
77
|
const TODO_KEY_CORRECTIONS = new Map<string, string>([
|
|
65
78
|
["note", 'note is an op, not a key; note operations require both "task" and "text"'],
|
|
66
79
|
["newTask", "there is no rename op; re-run init with the corrected list to rename a task"],
|
|
67
80
|
["tasks", 'tasks is not a key; append operations take "items"'],
|
|
81
|
+
["id", POSITIONAL_HANDLE_CORRECTION],
|
|
82
|
+
["ids", POSITIONAL_HANDLE_CORRECTION],
|
|
83
|
+
["index", POSITIONAL_HANDLE_CORRECTION],
|
|
84
|
+
["taskId", POSITIONAL_HANDLE_CORRECTION],
|
|
85
|
+
["task_id", POSITIONAL_HANDLE_CORRECTION],
|
|
68
86
|
]);
|
|
69
87
|
|
|
70
88
|
function unknownKeys(value: object, allowed: Set<string>): string[] {
|
|
@@ -72,15 +90,42 @@ function unknownKeys(value: object, allowed: Set<string>): string[] {
|
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
function keyRejectionDetail(keys: readonly string[], location?: string): RawArgumentRejectionDetail {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
93
|
+
const rejectedKeys = keys.slice(0, MAX_REJECTED_KEYS);
|
|
94
|
+
// Distinct corrections only. A family that shares one correction (every
|
|
95
|
+
// positional handle) would otherwise repeat it once per rejected key and blow
|
|
96
|
+
// past the caller's hint clamp, which truncates the advice mid-sentence.
|
|
97
|
+
const hints = [
|
|
98
|
+
...new Set(
|
|
99
|
+
keys
|
|
100
|
+
.map(key => TODO_KEY_CORRECTIONS.get(key) ?? TODO_KEY_CORRECTIONS.get(key.split(".").at(-1) ?? ""))
|
|
101
|
+
.filter((hint): hint is string => hint !== undefined),
|
|
102
|
+
),
|
|
103
|
+
];
|
|
104
|
+
const omitted = keys.length - rejectedKeys.length;
|
|
105
|
+
const parts = [
|
|
106
|
+
...(location === undefined ? [] : [location]),
|
|
107
|
+
...hints,
|
|
108
|
+
...(omitted > 0 ? [`${omitted} additional rejected keys omitted`] : []),
|
|
109
|
+
];
|
|
110
|
+
return parts.length > 0 ? { rejectedKeys, hint: parts.join("; ") } : { rejectedKeys };
|
|
78
111
|
}
|
|
79
112
|
|
|
80
113
|
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
81
114
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
82
115
|
}
|
|
83
116
|
|
|
117
|
+
function nestedPositionalHandleKeys(entry: Record<string, unknown>): string[] {
|
|
118
|
+
const keys: string[] = [];
|
|
119
|
+
for (const alias of ["task", "content"] as const) {
|
|
120
|
+
const value = entry[alias];
|
|
121
|
+
if (!isPlainRecord(value)) continue;
|
|
122
|
+
for (const key of Object.keys(value)) {
|
|
123
|
+
if (POSITIONAL_HANDLE_KEYS.has(key)) keys.push(`${alias}.${key}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return keys;
|
|
127
|
+
}
|
|
128
|
+
|
|
84
129
|
/**
|
|
85
130
|
* Single source of truth for todo_write pre-coercion validation. Every
|
|
86
131
|
* rejection carries a code so the caller can surface an actionable correction
|
|
@@ -119,6 +164,13 @@ export function validateRawTodoArguments(arguments_: Record<string, unknown>): R
|
|
|
119
164
|
code: "todo-write-unknown-op-entry-key",
|
|
120
165
|
detail: keyRejectionDetail(unknownEntryKeys, location),
|
|
121
166
|
};
|
|
167
|
+
const nestedHandles = nestedPositionalHandleKeys(entry);
|
|
168
|
+
if (nestedHandles.length > 0)
|
|
169
|
+
return {
|
|
170
|
+
outcome: "reject",
|
|
171
|
+
code: "todo-write-unknown-op-entry-key",
|
|
172
|
+
detail: keyRejectionDetail(nestedHandles, location),
|
|
173
|
+
};
|
|
122
174
|
const target = entry.task ?? entry.content;
|
|
123
175
|
if ((op === "done" || op === "drop") && !target && !entry.phase) {
|
|
124
176
|
return { outcome: "reject", code: "todo-write-done-drop-requires-target", detail: { hint: location } };
|
package/src/tools/todo-write.ts
CHANGED
|
@@ -539,9 +539,10 @@ export class TodoWriteTool implements AgentTool<typeof todoWriteSchema, TodoWrit
|
|
|
539
539
|
entry => (entry.op === "done" || entry.op === "drop") && !entry.task && !entry.phase,
|
|
540
540
|
);
|
|
541
541
|
if (missingTarget) {
|
|
542
|
-
//
|
|
543
|
-
//
|
|
544
|
-
//
|
|
542
|
+
// Model-issued calls never arrive here with a positional handle (`id: "1"`,
|
|
543
|
+
// `index: 2`): raw validation rejects the key first and carries the same
|
|
544
|
+
// correction. Bridges that call execute directly (eval's callSessionTool)
|
|
545
|
+
// skip that validation, so this still has to name what actually works.
|
|
545
546
|
const errors = [
|
|
546
547
|
`Missing task or phase for ${missingTarget.op} operation. ` +
|
|
547
548
|
`Pass "task" with the task's exact content, or "phase" with the phase name; ` +
|