@modelprofile.com/flexharness 10.2.0 → 10.3.0
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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.flexharness.js +11 -2
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/index.js +2 -2
- package/dist_ts/utils.slashcommands.js +3 -3
- package/package.json +3 -3
- package/readme.md +4 -4
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.flexharness.ts +15 -6
- package/ts/index.ts +2 -0
- package/ts/readme.md +4 -4
- package/ts/utils.slashcommands.ts +2 -2
package/dist_ts/index.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export * from './errors.js';
|
|
|
4
4
|
export * from './interfaces.js';
|
|
5
5
|
export { normalizeJsonValue } from './utils.json.js';
|
|
6
6
|
export { assertFlexProjectManagementSnapshot, assertFlexProjectManagementRecord, assertFlexProjectManagementTombstone, createEmptyFlexProjectManagementSnapshot, } from './utils.projectmanagement.js';
|
|
7
|
-
export { FLEX_SLASH_COMMAND_MAX_INPUT_BYTES, parseSlashCommand, } from './utils.slashcommands.js';
|
|
7
|
+
export { FLEX_SLASH_COMMAND_MAX_INPUT_BYTES, isReservedSlashCommandName, isValidSlashCommandName, parseSlashCommand, } from './utils.slashcommands.js';
|
package/dist_ts/index.js
CHANGED
|
@@ -4,5 +4,5 @@ export * from './errors.js';
|
|
|
4
4
|
export * from './interfaces.js';
|
|
5
5
|
export { normalizeJsonValue } from './utils.json.js';
|
|
6
6
|
export { assertFlexProjectManagementSnapshot, assertFlexProjectManagementRecord, assertFlexProjectManagementTombstone, createEmptyFlexProjectManagementSnapshot, } from './utils.projectmanagement.js';
|
|
7
|
-
export { FLEX_SLASH_COMMAND_MAX_INPUT_BYTES, parseSlashCommand, } from './utils.slashcommands.js';
|
|
8
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
7
|
+
export { FLEX_SLASH_COMMAND_MAX_INPUT_BYTES, isReservedSlashCommandName, isValidSlashCommandName, parseSlashCommand, } from './utils.slashcommands.js';
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNyRCxPQUFPLEVBQ0wsbUNBQW1DLEVBQ25DLGlDQUFpQyxFQUNqQyxvQ0FBb0MsRUFDcEMsd0NBQXdDLEdBQ3pDLE1BQU0sOEJBQThCLENBQUM7QUFDdEMsT0FBTyxFQUNMLGtDQUFrQyxFQUNsQywwQkFBMEIsRUFDMUIsdUJBQXVCLEVBQ3ZCLGlCQUFpQixHQUNsQixNQUFNLDBCQUEwQixDQUFDIn0=
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FlexHarnessValidationError } from './errors.js';
|
|
2
2
|
export const FLEX_SLASH_COMMAND_MAX_INPUT_BYTES = 768 * 1024;
|
|
3
|
-
const slashCommandNamePattern = /^[a-z][a-z0-
|
|
4
|
-
const slashCommandPattern = /^\/([a-z][a-z0-
|
|
3
|
+
const slashCommandNamePattern = /^[a-z][a-z0-9_-]{0,63}$/u;
|
|
4
|
+
const slashCommandPattern = /^\/([a-z][a-z0-9_-]{0,63})(?:$|(\s+)([\s\S]*))$/u;
|
|
5
5
|
const slashCommandArgumentsPattern = /(?:\[Image\s+\d+\]|"[^"]*"|'[^']*'|[^\s"']+)/gi;
|
|
6
6
|
const slashCommandQuoteTrimPattern = /^["']|["']$/g;
|
|
7
7
|
const slashCommandPlaceholderPattern = /\$(\d+)/g;
|
|
@@ -165,4 +165,4 @@ export function expandSlashCommandTemplate(template, rawArguments, arguments_) {
|
|
|
165
165
|
}
|
|
166
166
|
return expanded;
|
|
167
167
|
}
|
|
168
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
168
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuc2xhc2hjb21tYW5kcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3V0aWxzLnNsYXNoY29tbWFuZHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBTXpELE1BQU0sQ0FBQyxNQUFNLGtDQUFrQyxHQUFHLEdBQUcsR0FBRyxJQUFJLENBQUM7QUFFN0QsTUFBTSx1QkFBdUIsR0FBRywwQkFBMEIsQ0FBQztBQUMzRCxNQUFNLG1CQUFtQixHQUFHLGtEQUFrRCxDQUFDO0FBQy9FLE1BQU0sNEJBQTRCLEdBQUcsZ0RBQWdELENBQUM7QUFDdEYsTUFBTSw0QkFBNEIsR0FBRyxjQUFjLENBQUM7QUFDcEQsTUFBTSw4QkFBOEIsR0FBRyxVQUFVLENBQUM7QUFDbEQsTUFBTSxpQ0FBaUMsR0FBRyxzQkFBc0IsQ0FBQztBQUNqRSxNQUFNLHlCQUF5QixHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztBQUUvRSxNQUFNLENBQUMsTUFBTSxzQ0FBc0MsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0NBa0VyRCxDQUFDO0FBRUYsTUFBTSxVQUFVLHVCQUF1QixDQUFDLElBQVk7SUFDbEQsT0FBTyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDNUMsQ0FBQztBQUVELE1BQU0sVUFBVSwwQkFBMEIsQ0FBQyxJQUFZO0lBQ3JELE9BQU8seUJBQXlCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzdDLENBQUM7QUFFRCxTQUFTLDZCQUE2QixDQUFDLFlBQW9CO0lBQ3pELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxLQUFLLENBQUMsNEJBQTRCLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDdEUsT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLDRCQUE0QixFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDaEYsQ0FBQztBQUVELE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxLQUFhO0lBQzdDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDOUIsTUFBTSxJQUFJLDBCQUEwQixDQUFDLHVDQUF1QyxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUNELElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztRQUFFLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO0lBQzFFLElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLEdBQUcsa0NBQWtDLEVBQUUsQ0FBQztRQUMxRSxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7WUFDbkIsSUFBSSxFQUFFLFdBQVc7WUFDakIsTUFBTSxFQUFFLCtCQUErQixrQ0FBa0MsZUFBZTtTQUN6RixDQUFDLENBQUM7SUFDTCxDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNYLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQztZQUNuQixJQUFJLEVBQUUsV0FBVztZQUNqQixNQUFNLEVBQUUsa0NBQWtDO1NBQzNDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxNQUFNLFVBQVUsR0FBRyw2QkFBNkIsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDakUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUMxQixPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7UUFDbkIsSUFBSSxFQUFFLFFBQVE7UUFDZCxLQUFLO1FBQ0wsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDZCxZQUFZLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUU7UUFDNUIsU0FBUyxFQUFFLFVBQVU7S0FDWSxDQUFDLENBQUM7QUFDdkMsQ0FBQztBQUVELE1BQU0sVUFBVSx5QkFBeUIsQ0FBQyxRQUFnQjtJQUN4RCxNQUFNLEtBQUssR0FBRyxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2xFLElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUM7UUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzlELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVELE1BQU0sVUFBVSwwQkFBMEIsQ0FDeEMsUUFBZ0IsRUFDaEIsWUFBb0IsRUFDcEIsVUFBNkI7SUFFN0IsTUFBTSxZQUFZLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMxRSxJQUFJLGVBQWUsR0FBRyxDQUFDLENBQUM7SUFDeEIsS0FBSyxNQUFNLFdBQVcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUN2QyxlQUFlLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxlQUFlLEVBQUUsTUFBTSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzVFLENBQUM7SUFDRCxNQUFNLFFBQVEsR0FBYSxFQUFFLENBQUM7SUFDOUIsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0lBQ2xCLElBQUksYUFBYSxHQUFHLENBQUMsQ0FBQztJQUN0QixLQUFLLE1BQU0sS0FBSyxJQUFJLFFBQVEsQ0FBQyxRQUFRLENBQUMsaUNBQWlDLENBQUMsRUFBRSxDQUFDO1FBQ3pFLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2RCxJQUFJLFdBQW1CLENBQUM7UUFDeEIsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssWUFBWSxFQUFFLENBQUM7WUFDOUIsV0FBVyxHQUFHLFlBQVksQ0FBQztRQUM3QixDQUFDO2FBQU0sQ0FBQztZQUNOLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNsQyxNQUFNLGFBQWEsR0FBRyxRQUFRLEdBQUcsQ0FBQyxDQUFDO1lBQ25DLFdBQVcsR0FBRyxhQUFhLEdBQUcsQ0FBQyxJQUFJLGFBQWEsSUFBSSxVQUFVLENBQUMsTUFBTTtnQkFDbkUsQ0FBQyxDQUFDLEVBQUU7Z0JBQ0osQ0FBQyxDQUFDLFFBQVEsS0FBSyxlQUFlO29CQUM1QixDQUFDLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO29CQUMzQyxDQUFDLENBQUMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ2xDLENBQUM7UUFDRCxhQUFhLElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxXQUFXLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDN0YsSUFBSSxhQUFhLEdBQUcsa0NBQWtDLEVBQUUsQ0FBQztZQUN2RCxNQUFNLElBQUksMEJBQTBCLENBQUMsd0RBQXdELENBQUMsQ0FBQztRQUNqRyxDQUFDO1FBQ0QsUUFBUSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDcEMsU0FBUyxHQUFHLEtBQUssQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUM1QyxDQUFDO0lBQ0QsUUFBUSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDekMsYUFBYSxJQUFJLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzdELElBQUksYUFBYSxHQUFHLGtDQUFrQyxFQUFFLENBQUM7UUFDdkQsTUFBTSxJQUFJLDBCQUEwQixDQUFDLHdEQUF3RCxDQUFDLENBQUM7SUFDakcsQ0FBQztJQUNELElBQUksUUFBUSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDakMsSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLElBQUksWUFBWSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7UUFDekYsSUFDRSxhQUFhLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxZQUFZLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQztjQUN6RCxrQ0FBa0MsRUFDcEMsQ0FBQztZQUNELE1BQU0sSUFBSSwwQkFBMEIsQ0FBQyx3REFBd0QsQ0FBQyxDQUFDO1FBQ2pHLENBQUM7UUFDRCxRQUFRLElBQUksT0FBTyxZQUFZLEVBQUUsQ0FBQztJQUNwQyxDQUFDO0lBQ0QsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQyJ9
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "Task Venture Capital GmbH",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "@modelprofile.com/flexharness",
|
|
5
|
-
"version": "10.
|
|
5
|
+
"version": "10.3.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"description": "Managed agent sessions with tools, MCP, chat, OCR, documents and browser control through focused subpath imports.",
|
|
8
8
|
"main": "./dist_ts/index.js",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@modelprofile.com/flexharness-agent": "10.
|
|
74
|
-
"@modelprofile.com/flexharness-models": "10.
|
|
73
|
+
"@modelprofile.com/flexharness-agent": "10.3.0",
|
|
74
|
+
"@modelprofile.com/flexharness-models": "10.3.0",
|
|
75
75
|
"@push.rocks/smartrequest": "^5.5.1",
|
|
76
76
|
"ai": "^7.0.111",
|
|
77
77
|
"zod": "^4.6.5"
|
package/readme.md
CHANGED
|
@@ -642,7 +642,7 @@ The run takes a steer in at its next step boundary: after the tool results of it
|
|
|
642
642
|
|
|
643
643
|
## Slash Commands
|
|
644
644
|
|
|
645
|
-
`parseSlashCommand()` is the public strict pure parser. It accepts at most 768 KiB, returns `not-command` for input not starting with `/`, `malformed` for invalid slash syntax, and `parsed` with the exact input, lowercase command name, separator-stripped raw argument text, and OpenCode-compatible quoted tokenization. Command names match `[a-z][a-z0-
|
|
645
|
+
`parseSlashCommand()` is the public strict pure parser. It accepts at most 768 KiB, returns `not-command` for input not starting with `/`, `malformed` for invalid slash syntax, and `parsed` with the exact input, lowercase command name, separator-stripped raw argument text, and OpenCode-compatible quoted tokenization. Command names match `[a-z][a-z0-9_-]{0,63}`. The public `isValidSlashCommandName(name)` and `isReservedSlashCommandName(name)` helpers let applications validate registration names against the same rules. Single and double quotes group tokens and are stripped; escapes are not interpreted.
|
|
646
646
|
|
|
647
647
|
Applications register immutable custom commands at construction:
|
|
648
648
|
|
|
@@ -688,7 +688,7 @@ const harness = new FlexHarness({
|
|
|
688
688
|
|
|
689
689
|
`compact`, `init`, `undo`, and `redo` are reserved. `listSlashCommands()` verifies the scope and session and returns immutable data-only descriptors with `kind`, placeholder `hints`, current immediate availability, and `workspaceReversion`. `compact`, `undo`, `redo`, and custom handlers require an otherwise idle command session. Prompt templates and `init` use the normal bounded FIFO and may wait behind an active prompt. Their descriptors report availability from the same queue-admission conditions used by execution: lifecycle, slash ownership, pending reversion, root-session eligibility, outstanding count, and estimated prompt bytes. A dynamic capacity race may still produce `FlexHarnessQueueFullError` during admission. Only one slash-command execution may own a session at a time.
|
|
690
690
|
|
|
691
|
-
At most 128 custom commands may be registered. Every registration must be a plain object with exactly one of `template` or `handler`; names must match `[a-z][a-z0-
|
|
691
|
+
At most 128 custom commands may be registered. Every registration must be a plain object with exactly one of `template` or `handler`; names must match `[a-z][a-z0-9_-]{0,63}`, be unique, and not use a reserved name. Optional descriptions must be non-empty and at most 2048 UTF-8 bytes. Templates must be non-empty and at most 768 KiB, and the expanded prompt must also fit 768 KiB. Registrations are copied and frozen during construction.
|
|
692
692
|
|
|
693
693
|
`/undo` and `/redo`, plus `undoSession()` and `redoSession()`, move a durable history cursor. The direct methods return `{ revertedRunId }` and `{ restoredRunId }`; the slash forms return `{ type: 'operation', name: 'undo' | 'redo' }`. Each committed cursor move emits one `session.history.changed` event with `direction`, `runId`, and the selected session identity. A committed branch emits the same event with `direction: 'branch'` and no `runId`, so controllers should refresh the complete selected session. Capture finalization, cleanup, and metadata-only changes do not emit this event.
|
|
694
694
|
|
|
@@ -789,14 +789,14 @@ for (const group of info.groups) {
|
|
|
789
789
|
|
|
790
790
|
The immutable result exposes `undoAvailable`, `redoAvailable`, and groups classified as `candidate`, `barrier`, or `no-change`. Group metadata contains at most 64 unique affected workspaces; `affectedWorkspacesTruncated` is `true` when additional unique descriptors were omitted. It never includes capture IDs or provider references.
|
|
791
791
|
|
|
792
|
-
`workspaceSnapshots` is application-owned. Every context contains `scopeId`, `scope`, `storageKey`, `sessionId`, the required canonical `sessionGenerationId` and `sessionGenerationSequence`, `runId`, deterministic `captureId`, and an `AbortSignal`. Apply contexts additionally contain the normalized `reference`,
|
|
792
|
+
`workspaceSnapshots` is application-owned. Every context contains `scopeId`, `scope`, `storageKey`, `sessionId`, the required canonical `sessionGenerationId` and `sessionGenerationSequence`, `runId`, deterministic `captureId`, and an `AbortSignal`. Apply contexts additionally contain the normalized `reference`, per-segment `operationId`, and `direction`; release contexts contain the reference. Deleted-session recovery retains the same generation from the durable tombstone, so providers can reject callbacks from an older same-ID generation.
|
|
793
793
|
|
|
794
794
|
The protocol is durable and inspectable:
|
|
795
795
|
|
|
796
796
|
1. FlexHarness persists a `preparing` capture intent before calling `prepare()`, before model or tool execution. The provider must establish exclusive capture ownership for that `storageKey` and retain it until `release()` succeeds.
|
|
797
797
|
2. `inspectCapture()` returns `missing`, `prepared`, `finalized`, or `unknown`. A finalized V1 result includes `reference`; a finalized V2 result includes the complete tagged `outcome`. `missing` is safe only while the durable state is still `preparing`; a missing prepared or finalizing capture, an `unknown` result, or an inspection failure fences the namespace.
|
|
798
798
|
3. `finalize()` closes the capture and returns its JSON-safe V1 reference or complete V2 outcome. FlexHarness may call it during normal finalization or recovery after `inspectCapture()` reports `prepared`. Failed and cancelled root turns are captured too. A root capture spans its admitted subagent effects, including asynchronous children joined before finalization, although child transcript records remain separate. A failed parent cancels its outstanding children before joining them.
|
|
799
|
-
4. Before undo or redo, FlexHarness persists an apply write-ahead record. `inspectApply()` must report the exact durable outcome for the supplied `operationId`: `not-applied` means no effect occurred, `applied` means the complete effect occurred, and `unknown` means the provider cannot prove either result. FlexHarness calls `apply()` only for `not-applied`; after an apply error it inspects again, and an `unknown` result or inspection failure fences the namespace. Progress is persisted after each segment, and the transcript cursor moves only after the complete unit succeeds. Known zero-progress failures leave the cursor unchanged and can be retried; partial progress retains the write-ahead record and resumes after restart. Caller cancellation is honored until the first workspace segment makes progress; recovery then continues with fresh bounded maintenance signals until the unit and cursor commit.
|
|
799
|
+
4. Before undo or redo, FlexHarness persists an apply write-ahead record. `inspectApply()` must report the exact durable outcome for the supplied `operationId`: `not-applied` means no effect occurred, `applied` means the complete effect occurred, and `unknown` means the provider cannot prove either result. FlexHarness calls `apply()` only for `not-applied`; after an apply error it inspects again, and an `unknown` result or inspection failure fences the namespace. Progress is persisted after each segment, and the transcript cursor moves only after the complete unit succeeds. Known zero-progress failures leave the cursor unchanged and can be retried; partial progress retains the write-ahead record and resumes after restart. Caller cancellation is honored until the first workspace segment makes progress; recovery then continues with fresh bounded maintenance signals until the unit and cursor commit. Each `operationId` is unique to one apply of one segment: a later undo or redo gets a new ID even when it moves the same turn between the same cursors, such as undoing a turn again after a redo. Retries of that apply, in-process or after a restart, reuse its persisted ID, so providers must treat `operationId` idempotently and may record applied IDs to answer `inspectApply()`.
|
|
800
800
|
5. `release()` relinquishes the capture after no-change or nonrevertible V2 finalization, branch commitment, retention or archive pruning, session deletion, or other durable removal. It must be idempotent: an unacknowledged release remains persisted and is retried before FlexHarness discards the reference.
|
|
801
801
|
|
|
802
802
|
Under `workspace-required`, a group is a barrier when any segment is pending, nonrevertible, or legacy transcript-only history. It is a candidate when at least one segment is revertible and none is a barrier; otherwise it is no-change. Only candidates can be traversed. No-change groups after a candidate travel with that candidate until the next candidate or barrier. Leading no-change groups remain visible. A retained barrier blocks older groups, while later candidates remain undoable. A mixed revertible/nonrevertible group is a barrier.
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3511,13 +3511,22 @@ export class FlexHarness<TScope = unknown> {
|
|
|
3511
3511
|
'The turn has no available workspace reversion capture.',
|
|
3512
3512
|
);
|
|
3513
3513
|
}
|
|
3514
|
-
const operationId = this.reversionId(
|
|
3515
|
-
'apply',
|
|
3516
|
-
state.storageKey,
|
|
3517
|
-
sessionId,
|
|
3518
|
-
JSON.stringify([direction, stored.revertCursor, unit.toCursor, unit.target.runId]),
|
|
3519
|
-
);
|
|
3520
3514
|
await this.mutateProjection(state, stored, () => {
|
|
3515
|
+
// The write-ahead record commits at exactly projectionRevision + 1, so the
|
|
3516
|
+
// revision it replaces makes this apply's ID unique. Retries and recovery
|
|
3517
|
+
// read the persisted ID instead of deriving it again.
|
|
3518
|
+
const operationId = this.reversionId(
|
|
3519
|
+
'apply',
|
|
3520
|
+
state.storageKey,
|
|
3521
|
+
sessionId,
|
|
3522
|
+
JSON.stringify([
|
|
3523
|
+
direction,
|
|
3524
|
+
stored.revertCursor,
|
|
3525
|
+
unit.toCursor,
|
|
3526
|
+
unit.target.runId,
|
|
3527
|
+
stored.projectionRevision,
|
|
3528
|
+
]),
|
|
3529
|
+
);
|
|
3521
3530
|
stored.pendingReversion = {
|
|
3522
3531
|
kind: 'apply',
|
|
3523
3532
|
operationId,
|
package/ts/index.ts
CHANGED
package/ts/readme.md
CHANGED
|
@@ -642,7 +642,7 @@ The run takes a steer in at its next step boundary: after the tool results of it
|
|
|
642
642
|
|
|
643
643
|
## Slash Commands
|
|
644
644
|
|
|
645
|
-
`parseSlashCommand()` is the public strict pure parser. It accepts at most 768 KiB, returns `not-command` for input not starting with `/`, `malformed` for invalid slash syntax, and `parsed` with the exact input, lowercase command name, separator-stripped raw argument text, and OpenCode-compatible quoted tokenization. Command names match `[a-z][a-z0-
|
|
645
|
+
`parseSlashCommand()` is the public strict pure parser. It accepts at most 768 KiB, returns `not-command` for input not starting with `/`, `malformed` for invalid slash syntax, and `parsed` with the exact input, lowercase command name, separator-stripped raw argument text, and OpenCode-compatible quoted tokenization. Command names match `[a-z][a-z0-9_-]{0,63}`. The public `isValidSlashCommandName(name)` and `isReservedSlashCommandName(name)` helpers let applications validate registration names against the same rules. Single and double quotes group tokens and are stripped; escapes are not interpreted.
|
|
646
646
|
|
|
647
647
|
Applications register immutable custom commands at construction:
|
|
648
648
|
|
|
@@ -688,7 +688,7 @@ const harness = new FlexHarness({
|
|
|
688
688
|
|
|
689
689
|
`compact`, `init`, `undo`, and `redo` are reserved. `listSlashCommands()` verifies the scope and session and returns immutable data-only descriptors with `kind`, placeholder `hints`, current immediate availability, and `workspaceReversion`. `compact`, `undo`, `redo`, and custom handlers require an otherwise idle command session. Prompt templates and `init` use the normal bounded FIFO and may wait behind an active prompt. Their descriptors report availability from the same queue-admission conditions used by execution: lifecycle, slash ownership, pending reversion, root-session eligibility, outstanding count, and estimated prompt bytes. A dynamic capacity race may still produce `FlexHarnessQueueFullError` during admission. Only one slash-command execution may own a session at a time.
|
|
690
690
|
|
|
691
|
-
At most 128 custom commands may be registered. Every registration must be a plain object with exactly one of `template` or `handler`; names must match `[a-z][a-z0-
|
|
691
|
+
At most 128 custom commands may be registered. Every registration must be a plain object with exactly one of `template` or `handler`; names must match `[a-z][a-z0-9_-]{0,63}`, be unique, and not use a reserved name. Optional descriptions must be non-empty and at most 2048 UTF-8 bytes. Templates must be non-empty and at most 768 KiB, and the expanded prompt must also fit 768 KiB. Registrations are copied and frozen during construction.
|
|
692
692
|
|
|
693
693
|
`/undo` and `/redo`, plus `undoSession()` and `redoSession()`, move a durable history cursor. The direct methods return `{ revertedRunId }` and `{ restoredRunId }`; the slash forms return `{ type: 'operation', name: 'undo' | 'redo' }`. Each committed cursor move emits one `session.history.changed` event with `direction`, `runId`, and the selected session identity. A committed branch emits the same event with `direction: 'branch'` and no `runId`, so controllers should refresh the complete selected session. Capture finalization, cleanup, and metadata-only changes do not emit this event.
|
|
694
694
|
|
|
@@ -789,14 +789,14 @@ for (const group of info.groups) {
|
|
|
789
789
|
|
|
790
790
|
The immutable result exposes `undoAvailable`, `redoAvailable`, and groups classified as `candidate`, `barrier`, or `no-change`. Group metadata contains at most 64 unique affected workspaces; `affectedWorkspacesTruncated` is `true` when additional unique descriptors were omitted. It never includes capture IDs or provider references.
|
|
791
791
|
|
|
792
|
-
`workspaceSnapshots` is application-owned. Every context contains `scopeId`, `scope`, `storageKey`, `sessionId`, the required canonical `sessionGenerationId` and `sessionGenerationSequence`, `runId`, deterministic `captureId`, and an `AbortSignal`. Apply contexts additionally contain the normalized `reference`,
|
|
792
|
+
`workspaceSnapshots` is application-owned. Every context contains `scopeId`, `scope`, `storageKey`, `sessionId`, the required canonical `sessionGenerationId` and `sessionGenerationSequence`, `runId`, deterministic `captureId`, and an `AbortSignal`. Apply contexts additionally contain the normalized `reference`, per-segment `operationId`, and `direction`; release contexts contain the reference. Deleted-session recovery retains the same generation from the durable tombstone, so providers can reject callbacks from an older same-ID generation.
|
|
793
793
|
|
|
794
794
|
The protocol is durable and inspectable:
|
|
795
795
|
|
|
796
796
|
1. FlexHarness persists a `preparing` capture intent before calling `prepare()`, before model or tool execution. The provider must establish exclusive capture ownership for that `storageKey` and retain it until `release()` succeeds.
|
|
797
797
|
2. `inspectCapture()` returns `missing`, `prepared`, `finalized`, or `unknown`. A finalized V1 result includes `reference`; a finalized V2 result includes the complete tagged `outcome`. `missing` is safe only while the durable state is still `preparing`; a missing prepared or finalizing capture, an `unknown` result, or an inspection failure fences the namespace.
|
|
798
798
|
3. `finalize()` closes the capture and returns its JSON-safe V1 reference or complete V2 outcome. FlexHarness may call it during normal finalization or recovery after `inspectCapture()` reports `prepared`. Failed and cancelled root turns are captured too. A root capture spans its admitted subagent effects, including asynchronous children joined before finalization, although child transcript records remain separate. A failed parent cancels its outstanding children before joining them.
|
|
799
|
-
4. Before undo or redo, FlexHarness persists an apply write-ahead record. `inspectApply()` must report the exact durable outcome for the supplied `operationId`: `not-applied` means no effect occurred, `applied` means the complete effect occurred, and `unknown` means the provider cannot prove either result. FlexHarness calls `apply()` only for `not-applied`; after an apply error it inspects again, and an `unknown` result or inspection failure fences the namespace. Progress is persisted after each segment, and the transcript cursor moves only after the complete unit succeeds. Known zero-progress failures leave the cursor unchanged and can be retried; partial progress retains the write-ahead record and resumes after restart. Caller cancellation is honored until the first workspace segment makes progress; recovery then continues with fresh bounded maintenance signals until the unit and cursor commit.
|
|
799
|
+
4. Before undo or redo, FlexHarness persists an apply write-ahead record. `inspectApply()` must report the exact durable outcome for the supplied `operationId`: `not-applied` means no effect occurred, `applied` means the complete effect occurred, and `unknown` means the provider cannot prove either result. FlexHarness calls `apply()` only for `not-applied`; after an apply error it inspects again, and an `unknown` result or inspection failure fences the namespace. Progress is persisted after each segment, and the transcript cursor moves only after the complete unit succeeds. Known zero-progress failures leave the cursor unchanged and can be retried; partial progress retains the write-ahead record and resumes after restart. Caller cancellation is honored until the first workspace segment makes progress; recovery then continues with fresh bounded maintenance signals until the unit and cursor commit. Each `operationId` is unique to one apply of one segment: a later undo or redo gets a new ID even when it moves the same turn between the same cursors, such as undoing a turn again after a redo. Retries of that apply, in-process or after a restart, reuse its persisted ID, so providers must treat `operationId` idempotently and may record applied IDs to answer `inspectApply()`.
|
|
800
800
|
5. `release()` relinquishes the capture after no-change or nonrevertible V2 finalization, branch commitment, retention or archive pruning, session deletion, or other durable removal. It must be idempotent: an unacknowledged release remains persisted and is retried before FlexHarness discards the reference.
|
|
801
801
|
|
|
802
802
|
Under `workspace-required`, a group is a barrier when any segment is pending, nonrevertible, or legacy transcript-only history. It is a candidate when at least one segment is revertible and none is a barrier; otherwise it is no-change. Only candidates can be traversed. No-change groups after a candidate travel with that candidate until the next candidate or barrier. Leading no-change groups remain visible. A retained barrier blocks older groups, while later candidates remain undoable. A mixed revertible/nonrevertible group is a barrier.
|
|
@@ -6,8 +6,8 @@ import type {
|
|
|
6
6
|
|
|
7
7
|
export const FLEX_SLASH_COMMAND_MAX_INPUT_BYTES = 768 * 1024;
|
|
8
8
|
|
|
9
|
-
const slashCommandNamePattern = /^[a-z][a-z0-
|
|
10
|
-
const slashCommandPattern = /^\/([a-z][a-z0-
|
|
9
|
+
const slashCommandNamePattern = /^[a-z][a-z0-9_-]{0,63}$/u;
|
|
10
|
+
const slashCommandPattern = /^\/([a-z][a-z0-9_-]{0,63})(?:$|(\s+)([\s\S]*))$/u;
|
|
11
11
|
const slashCommandArgumentsPattern = /(?:\[Image\s+\d+\]|"[^"]*"|'[^']*'|[^\s"']+)/gi;
|
|
12
12
|
const slashCommandQuoteTrimPattern = /^["']|["']$/g;
|
|
13
13
|
const slashCommandPlaceholderPattern = /\$(\d+)/g;
|