oh-my-opencode 5.1.60 → 5.1.62
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/.agents/command/remove-deadcode.md +1 -1
- package/.agents/skills/remove-deadcode/SKILL.md +1 -1
- package/.opencode/command/remove-deadcode.md +1 -1
- package/dist/cli/index.js +181 -32
- package/dist/cli/service-auth/index.d.ts +2 -1
- package/dist/cli/service-auth/session.d.ts +27 -0
- package/dist/cli/service-auth/sync-pin-retire.d.ts +7 -0
- package/dist/cli-node/index.js +181 -32
- package/dist/config/schema/agent-names.d.ts +1 -0
- package/dist/index.js +2029 -1406
- package/dist/skills/browser/references/owned-engine/README.md +1 -1
- package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
- package/dist/skills/frontend/SKILL.md +2 -2
- package/dist/skills/frontend/references/design/README.md +2 -2
- package/dist/skills/frontend/references/design/component-catalogs.md +1 -1
- package/dist/skills/frontend/references/design/design-system-architecture.md +1 -1
- package/dist/skills/frontend/references/design/react-dev-tooling-skill.md +1 -1
- package/dist/skills/frontend/references/designpowers/lane-a-direction.md +5 -5
- package/dist/skills/frontend/references/designpowers/routing.md +2 -2
- package/dist/skills/frontend/references/perfection/README.md +1 -1
- package/dist/skills/programming/references/python/libraries.md +3 -3
- package/dist/skills/programming/references/python/one-liners.md +1 -1
- package/dist/skills/programming/references/python/pyproject-strict.md +1 -1
- package/dist/skills/programming/references/rust/libraries.md +2 -2
- package/dist/skills/refactor/SKILL.md +1 -1
- package/dist/skills/ultimate-browsing/SKILL.md +1 -1
- package/dist/skills/ultimate-browsing/references/insane-search/README.md +1 -1
- package/dist/skills/ulw-execute/SKILL.md +1 -1
- package/dist/skills/ulw-research/SKILL.md +2 -2
- package/dist/tui.js +41 -19
- package/package.json +14 -14
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +13 -0
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/skills/browser/references/owned-engine/README.md +1 -1
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/react-dev-tooling-skill.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +5 -5
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/perfection/README.md +1 -1
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/references/python/libraries.md +3 -3
- package/packages/omo-codex/plugin/skills/programming/references/python/one-liners.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/references/python/pyproject-strict.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/references/rust/libraries.md +2 -2
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +15 -2
- package/packages/shared-skills/skills/browser/references/owned-engine/README.md +1 -1
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/react-dev-tooling-skill.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +5 -5
- package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +2 -2
- package/packages/shared-skills/skills/frontend/references/perfection/README.md +1 -1
- package/packages/shared-skills/skills/programming/references/python/libraries.md +3 -3
- package/packages/shared-skills/skills/programming/references/python/one-liners.md +1 -1
- package/packages/shared-skills/skills/programming/references/python/pyproject-strict.md +1 -1
- package/packages/shared-skills/skills/programming/references/rust/libraries.md +2 -2
- package/packages/shared-skills/skills/refactor/SKILL.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +1 -1
- package/packages/shared-skills/skills/ulw-execute/SKILL.md +1 -1
- package/packages/shared-skills/skills/ulw-research/SKILL.md +2 -2
- package/.opencode/skills/hyperplan/SKILL.md +0 -450
|
@@ -114,7 +114,7 @@ For EACH batch, fire a deep agent:
|
|
|
114
114
|
```
|
|
115
115
|
task(
|
|
116
116
|
category="deep-low",
|
|
117
|
-
load_skills=["
|
|
117
|
+
load_skills=["programming", "git-master"],
|
|
118
118
|
run_in_background=true,
|
|
119
119
|
description="Remove dead code batch N: [brief description]",
|
|
120
120
|
prompt="[see template below]"
|
|
@@ -114,7 +114,7 @@ For EACH batch, fire a deep agent:
|
|
|
114
114
|
```
|
|
115
115
|
task(
|
|
116
116
|
category="deep-low",
|
|
117
|
-
load_skills=["
|
|
117
|
+
load_skills=["programming", "git-master"],
|
|
118
118
|
run_in_background=true,
|
|
119
119
|
description="Remove dead code batch N: [brief description]",
|
|
120
120
|
prompt="[see template below]"
|
|
@@ -114,7 +114,7 @@ For EACH batch, fire a deep agent:
|
|
|
114
114
|
```
|
|
115
115
|
task(
|
|
116
116
|
category="deep",
|
|
117
|
-
load_skills=["
|
|
117
|
+
load_skills=["programming", "git-master"],
|
|
118
118
|
run_in_background=true,
|
|
119
119
|
description="Remove dead code batch N: [brief description]",
|
|
120
120
|
prompt="[see template below]"
|
package/dist/cli/index.js
CHANGED
|
@@ -2132,7 +2132,7 @@ var package_default;
|
|
|
2132
2132
|
var init_package = __esm(() => {
|
|
2133
2133
|
package_default = {
|
|
2134
2134
|
name: "oh-my-opencode",
|
|
2135
|
-
version: "5.1.
|
|
2135
|
+
version: "5.1.62",
|
|
2136
2136
|
description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
2137
2137
|
main: "./dist/index.js",
|
|
2138
2138
|
types: "dist/index.d.ts",
|
|
@@ -2319,7 +2319,7 @@ var init_package = __esm(() => {
|
|
|
2319
2319
|
},
|
|
2320
2320
|
devDependencies: {
|
|
2321
2321
|
"@clack/prompts": "^1.8.1",
|
|
2322
|
-
"@code-yeongyu/senpi": "2026.11.
|
|
2322
|
+
"@code-yeongyu/senpi": "2026.11.5-1",
|
|
2323
2323
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
2324
2324
|
"@oh-my-opencode/agents-md-core": "workspace:*",
|
|
2325
2325
|
"@oh-my-opencode/ast-grep-mcp": "workspace:*",
|
|
@@ -2384,18 +2384,18 @@ var init_package = __esm(() => {
|
|
|
2384
2384
|
typescript: "^7.0.2"
|
|
2385
2385
|
},
|
|
2386
2386
|
optionalDependencies: {
|
|
2387
|
-
"oh-my-opencode-darwin-arm64": "5.1.
|
|
2388
|
-
"oh-my-opencode-darwin-x64": "5.1.
|
|
2389
|
-
"oh-my-opencode-darwin-x64-baseline": "5.1.
|
|
2390
|
-
"oh-my-opencode-linux-arm64": "5.1.
|
|
2391
|
-
"oh-my-opencode-linux-arm64-musl": "5.1.
|
|
2392
|
-
"oh-my-opencode-linux-x64": "5.1.
|
|
2393
|
-
"oh-my-opencode-linux-x64-baseline": "5.1.
|
|
2394
|
-
"oh-my-opencode-linux-x64-musl": "5.1.
|
|
2395
|
-
"oh-my-opencode-linux-x64-musl-baseline": "5.1.
|
|
2396
|
-
"oh-my-opencode-windows-arm64": "5.1.
|
|
2397
|
-
"oh-my-opencode-windows-x64": "5.1.
|
|
2398
|
-
"oh-my-opencode-windows-x64-baseline": "5.1.
|
|
2387
|
+
"oh-my-opencode-darwin-arm64": "5.1.62",
|
|
2388
|
+
"oh-my-opencode-darwin-x64": "5.1.62",
|
|
2389
|
+
"oh-my-opencode-darwin-x64-baseline": "5.1.62",
|
|
2390
|
+
"oh-my-opencode-linux-arm64": "5.1.62",
|
|
2391
|
+
"oh-my-opencode-linux-arm64-musl": "5.1.62",
|
|
2392
|
+
"oh-my-opencode-linux-x64": "5.1.62",
|
|
2393
|
+
"oh-my-opencode-linux-x64-baseline": "5.1.62",
|
|
2394
|
+
"oh-my-opencode-linux-x64-musl": "5.1.62",
|
|
2395
|
+
"oh-my-opencode-linux-x64-musl-baseline": "5.1.62",
|
|
2396
|
+
"oh-my-opencode-windows-arm64": "5.1.62",
|
|
2397
|
+
"oh-my-opencode-windows-x64": "5.1.62",
|
|
2398
|
+
"oh-my-opencode-windows-x64-baseline": "5.1.62"
|
|
2399
2399
|
},
|
|
2400
2400
|
overrides: {
|
|
2401
2401
|
hono: "^4.13.8",
|
|
@@ -7490,7 +7490,7 @@ function createLogger(options) {
|
|
|
7490
7490
|
function scheduleFlush() {
|
|
7491
7491
|
if (flushTimer)
|
|
7492
7492
|
return;
|
|
7493
|
-
flushTimer =
|
|
7493
|
+
flushTimer = scheduleTimeout(() => {
|
|
7494
7494
|
flushTimer = null;
|
|
7495
7495
|
flush();
|
|
7496
7496
|
}, flushIntervalMs);
|
|
@@ -7517,7 +7517,7 @@ function createLogger(options) {
|
|
|
7517
7517
|
function _setLoggerForTesting(overrides) {
|
|
7518
7518
|
buffer = [];
|
|
7519
7519
|
if (flushTimer) {
|
|
7520
|
-
|
|
7520
|
+
cancelTimeout(flushTimer);
|
|
7521
7521
|
flushTimer = null;
|
|
7522
7522
|
}
|
|
7523
7523
|
if (overrides.filePath !== undefined)
|
|
@@ -7533,13 +7533,13 @@ function createLogger(options) {
|
|
|
7533
7533
|
maxLogFileBackups = maxLogFileBackupsDefault;
|
|
7534
7534
|
buffer = [];
|
|
7535
7535
|
if (flushTimer) {
|
|
7536
|
-
|
|
7536
|
+
cancelTimeout(flushTimer);
|
|
7537
7537
|
flushTimer = null;
|
|
7538
7538
|
}
|
|
7539
7539
|
}
|
|
7540
7540
|
function _flushForTesting() {
|
|
7541
7541
|
if (flushTimer) {
|
|
7542
|
-
|
|
7542
|
+
cancelTimeout(flushTimer);
|
|
7543
7543
|
flushTimer = null;
|
|
7544
7544
|
}
|
|
7545
7545
|
flush();
|
|
@@ -7552,8 +7552,10 @@ function createLogger(options) {
|
|
|
7552
7552
|
_flushForTesting
|
|
7553
7553
|
};
|
|
7554
7554
|
}
|
|
7555
|
-
var DEFAULT_MAX_LOG_FILE_SIZE_BYTES, DEFAULT_MAX_LOG_FILE_BACKUPS = 2, DEFAULT_LOG_FLUSH_INTERVAL_MS = 500, DEFAULT_LOG_BUFFER_SIZE_LIMIT = 50;
|
|
7555
|
+
var scheduleTimeout, cancelTimeout, DEFAULT_MAX_LOG_FILE_SIZE_BYTES, DEFAULT_MAX_LOG_FILE_BACKUPS = 2, DEFAULT_LOG_FLUSH_INTERVAL_MS = 500, DEFAULT_LOG_BUFFER_SIZE_LIMIT = 50;
|
|
7556
7556
|
var init_logger = __esm(() => {
|
|
7557
|
+
scheduleTimeout = globalThis.setTimeout;
|
|
7558
|
+
cancelTimeout = globalThis.clearTimeout;
|
|
7557
7559
|
DEFAULT_MAX_LOG_FILE_SIZE_BYTES = 50 * 1024 * 1024;
|
|
7558
7560
|
});
|
|
7559
7561
|
|
|
@@ -77637,6 +77639,19 @@ var init_telemetry = __esm(() => {
|
|
|
77637
77639
|
}).strict();
|
|
77638
77640
|
});
|
|
77639
77641
|
|
|
77642
|
+
// packages/omo-config-core/src/schema/device-service.ts
|
|
77643
|
+
var OmoDeviceServiceSettingsShape, OmoDeviceServiceSettingsLayerSchema, OmoDeviceServiceSettingsSchema;
|
|
77644
|
+
var init_device_service = __esm(() => {
|
|
77645
|
+
init_zod();
|
|
77646
|
+
OmoDeviceServiceSettingsShape = {
|
|
77647
|
+
enabled: boolean2()
|
|
77648
|
+
};
|
|
77649
|
+
OmoDeviceServiceSettingsLayerSchema = object(OmoDeviceServiceSettingsShape).partial().strict();
|
|
77650
|
+
OmoDeviceServiceSettingsSchema = OmoDeviceServiceSettingsLayerSchema.extend({
|
|
77651
|
+
enabled: boolean2().default(true)
|
|
77652
|
+
}).strict();
|
|
77653
|
+
});
|
|
77654
|
+
|
|
77640
77655
|
// packages/omo-config-core/src/schema/format-on-mutation.ts
|
|
77641
77656
|
var mode, languages, OmoFormatOnMutationLayerSchema, OmoFormatOnMutationSchema;
|
|
77642
77657
|
var init_format_on_mutation = __esm(() => {
|
|
@@ -77685,6 +77700,7 @@ var init_config = __esm(() => {
|
|
|
77685
77700
|
init_task();
|
|
77686
77701
|
init_team();
|
|
77687
77702
|
init_telemetry();
|
|
77703
|
+
init_device_service();
|
|
77688
77704
|
init_format_on_mutation();
|
|
77689
77705
|
init_provenance();
|
|
77690
77706
|
OmoOpenCodeHarnessConfigSchema = record(string2(), unknown());
|
|
@@ -77704,6 +77720,7 @@ var init_config = __esm(() => {
|
|
|
77704
77720
|
model_pad: OmoModelPadSchema.optional(),
|
|
77705
77721
|
memory: OmoMemorySettingsLayerSchema.optional(),
|
|
77706
77722
|
telemetry: OmoTelemetrySettingsLayerSchema.optional(),
|
|
77723
|
+
device_service: OmoDeviceServiceSettingsLayerSchema.optional(),
|
|
77707
77724
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
77708
77725
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
77709
77726
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
@@ -77723,6 +77740,7 @@ var init_config = __esm(() => {
|
|
|
77723
77740
|
model_pad: OmoModelPadSchema.optional(),
|
|
77724
77741
|
memory: OmoMemorySettingsLayerSchema.optional(),
|
|
77725
77742
|
telemetry: OmoTelemetrySettingsLayerSchema.optional(),
|
|
77743
|
+
device_service: OmoDeviceServiceSettingsLayerSchema.optional(),
|
|
77726
77744
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
77727
77745
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
77728
77746
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
@@ -77747,6 +77765,7 @@ var init_config = __esm(() => {
|
|
|
77747
77765
|
model_pad: OmoModelPadSchema.optional(),
|
|
77748
77766
|
memory: OmoMemorySettingsSchema.optional(),
|
|
77749
77767
|
telemetry: OmoTelemetrySettingsSchema.optional(),
|
|
77768
|
+
device_service: OmoDeviceServiceSettingsSchema.optional(),
|
|
77750
77769
|
side_panel: OmoSidePanelSettingsSchema.optional(),
|
|
77751
77770
|
computer: OmoComputerSettingsSchema.optional(),
|
|
77752
77771
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
@@ -77774,6 +77793,7 @@ var init_config = __esm(() => {
|
|
|
77774
77793
|
model_pad: OmoModelPadSchema.optional(),
|
|
77775
77794
|
memory: OmoMemorySettingsLayerSchema.optional(),
|
|
77776
77795
|
telemetry: OmoTelemetrySettingsLayerSchema.optional(),
|
|
77796
|
+
device_service: OmoDeviceServiceSettingsLayerSchema.optional(),
|
|
77777
77797
|
side_panel: OmoSidePanelSettingsLayerSchema.optional(),
|
|
77778
77798
|
computer: OmoComputerSettingsLayerSchema.optional(),
|
|
77779
77799
|
disabled_skills: OmoDisabledSkillsSchema.optional(),
|
|
@@ -77925,6 +77945,7 @@ var init_schema = __esm(() => {
|
|
|
77925
77945
|
init_task();
|
|
77926
77946
|
init_team();
|
|
77927
77947
|
init_telemetry();
|
|
77948
|
+
init_device_service();
|
|
77928
77949
|
init_computer();
|
|
77929
77950
|
});
|
|
77930
77951
|
|
|
@@ -92689,7 +92710,7 @@ var package_default2;
|
|
|
92689
92710
|
var init_package2 = __esm(() => {
|
|
92690
92711
|
package_default2 = {
|
|
92691
92712
|
name: "@oh-my-opencode/omo-codex",
|
|
92692
|
-
version: "5.1.
|
|
92713
|
+
version: "5.1.62",
|
|
92693
92714
|
type: "module",
|
|
92694
92715
|
private: true,
|
|
92695
92716
|
description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
|
|
@@ -100065,6 +100086,7 @@ var REQUIRED_PLUGIN_ARTIFACTS = [
|
|
|
100065
100086
|
join66("extensions", "omo-memory-commands.js"),
|
|
100066
100087
|
join66("extensions", "omo-session-history.js"),
|
|
100067
100088
|
join66("extensions", "omo-recall-store.js"),
|
|
100089
|
+
join66("extensions", "omo-device-service.js"),
|
|
100068
100090
|
join66("extensions", "omo-telemetry-posthog.js"),
|
|
100069
100091
|
join66("extensions", "omo-telemetry-otlp.js"),
|
|
100070
100092
|
join66("extensions", "omo-memory-sync.js"),
|
|
@@ -104351,6 +104373,7 @@ var BuiltinSkillNameSchema = _enum([
|
|
|
104351
104373
|
"debugging",
|
|
104352
104374
|
"security-research",
|
|
104353
104375
|
"security-review",
|
|
104376
|
+
"hyperplan",
|
|
104354
104377
|
"visual-qa",
|
|
104355
104378
|
"team-mode"
|
|
104356
104379
|
]);
|
|
@@ -109449,8 +109472,8 @@ var package_default3 = {
|
|
|
109449
109472
|
},
|
|
109450
109473
|
dependencies: {
|
|
109451
109474
|
"@clack/prompts": "^1.8.1",
|
|
109452
|
-
"@code-yeongyu/senpi": "2026.11.
|
|
109453
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.11.
|
|
109475
|
+
"@code-yeongyu/senpi": "2026.11.5-1",
|
|
109476
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.11.5-1",
|
|
109454
109477
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
109455
109478
|
"@oh-my-opencode/agents-md-core": "workspace:*",
|
|
109456
109479
|
"@oh-my-opencode/boulder-state": "workspace:*",
|
|
@@ -112722,6 +112745,24 @@ function retryOnEintrSync(operation) {
|
|
|
112722
112745
|
|
|
112723
112746
|
// packages/memory-core/src/fs/rename-contention.ts
|
|
112724
112747
|
var CONTENTION_CODES = new Set(["EPERM", "EBUSY", "EACCES"]);
|
|
112748
|
+
var CONTENTION_DELAYS_MS = [10, 25, 50, 100, 200, 400];
|
|
112749
|
+
var sleepFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
112750
|
+
async function renameWithContentionRetry(from, to, deps) {
|
|
112751
|
+
const delays = deps.platform === "win32" ? deps.delaysMs ?? CONTENTION_DELAYS_MS : [];
|
|
112752
|
+
const sleep = deps.sleep ?? sleepFor;
|
|
112753
|
+
for (let attempt = 0;; attempt += 1) {
|
|
112754
|
+
try {
|
|
112755
|
+
await retryOnEintr(() => deps.admit === undefined ? deps.rename(from, to) : deps.admit(() => deps.rename(from, to)));
|
|
112756
|
+
return;
|
|
112757
|
+
} catch (error) {
|
|
112758
|
+
const delay = delays[attempt];
|
|
112759
|
+
const code = fsErrorCode(error);
|
|
112760
|
+
if (delay === undefined || code === undefined || !CONTENTION_CODES.has(code))
|
|
112761
|
+
throw error;
|
|
112762
|
+
await sleep(delay);
|
|
112763
|
+
}
|
|
112764
|
+
}
|
|
112765
|
+
}
|
|
112725
112766
|
|
|
112726
112767
|
// packages/memory-core/src/fs/resilient.ts
|
|
112727
112768
|
function isFunction2(value) {
|
|
@@ -112754,6 +112795,13 @@ function resilientNamespace(namespace, kind) {
|
|
|
112754
112795
|
}
|
|
112755
112796
|
var IDEMPOTENT_HANDLE_METHODS = new Set(["stat", "sync", "datasync", "chmod", "chown", "utimes", "truncate"]);
|
|
112756
112797
|
var promises = resilientNamespace(fsp, "async");
|
|
112798
|
+
function rename8(from, to, admit) {
|
|
112799
|
+
return renameWithContentionRetry(from, to, {
|
|
112800
|
+
rename: (source, target) => fsp.rename(source, target),
|
|
112801
|
+
platform: process.platform,
|
|
112802
|
+
...admit === undefined ? {} : { admit }
|
|
112803
|
+
});
|
|
112804
|
+
}
|
|
112757
112805
|
var sync = resilientNamespace(fsSync, "sync");
|
|
112758
112806
|
var {
|
|
112759
112807
|
access: access3,
|
|
@@ -113649,15 +113697,60 @@ async function loginLoopback(session, options) {
|
|
|
113649
113697
|
}
|
|
113650
113698
|
}
|
|
113651
113699
|
|
|
113652
|
-
// packages/
|
|
113700
|
+
// packages/memory-core/src/sync/device-retire.ts
|
|
113701
|
+
import { createHash as createHash14, randomBytes as randomBytes6 } from "crypto";
|
|
113702
|
+
import { join as join109 } from "path";
|
|
113703
|
+
|
|
113704
|
+
// packages/memory-core/src/identity/layout.ts
|
|
113653
113705
|
import { homedir as homedir32 } from "os";
|
|
113706
|
+
import { join as join107, resolve as resolve31 } from "path";
|
|
113707
|
+
var MEMORY_ROOT_ENV_VAR = "OMO_MEMORY_HOME";
|
|
113708
|
+
function defaultMemoryRoot() {
|
|
113709
|
+
return join107(homedir32(), ".omo", "memory");
|
|
113710
|
+
}
|
|
113711
|
+
function resolveMemoryRoot(env, cwd) {
|
|
113712
|
+
const override = env[MEMORY_ROOT_ENV_VAR];
|
|
113713
|
+
if (override === undefined || override.trim() === "") {
|
|
113714
|
+
return defaultMemoryRoot();
|
|
113715
|
+
}
|
|
113716
|
+
return resolve31(cwd, override);
|
|
113717
|
+
}
|
|
113718
|
+
// packages/memory-core/src/sync/pin-dir.ts
|
|
113719
|
+
import { join as join108 } from "path";
|
|
113720
|
+
var syncPinDir = (memoryRoot) => join108(memoryRoot, "sync-device");
|
|
113721
|
+
|
|
113722
|
+
// packages/memory-core/src/sync/device-retire.ts
|
|
113723
|
+
var trustAnchorRoot = (pinDir) => join109(pinDir, "trust-anchor");
|
|
113724
|
+
var trustAnchorKey = (account) => createHash14("sha256").update(account, "utf8").digest("base64url");
|
|
113725
|
+
var trustAnchorDir = (pinDir, account) => join109(trustAnchorRoot(pinDir), trustAnchorKey(account));
|
|
113726
|
+
var hasLiveTrustAnchor = async (pinDir) => {
|
|
113727
|
+
try {
|
|
113728
|
+
return (await readdir17(trustAnchorRoot(pinDir))).some((name) => !name.includes(".retired-"));
|
|
113729
|
+
} catch (error) {
|
|
113730
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
113731
|
+
return false;
|
|
113732
|
+
throw error;
|
|
113733
|
+
}
|
|
113734
|
+
};
|
|
113735
|
+
var retireSyncDevice = async (input) => {
|
|
113736
|
+
const dir = trustAnchorDir(input.pinDir, input.account);
|
|
113737
|
+
try {
|
|
113738
|
+
await rename8(dir, `${dir}.retired-${Date.now()}-${randomBytes6(4).toString("hex")}`);
|
|
113739
|
+
} catch (error) {
|
|
113740
|
+
if (!(error instanceof Error && ("code" in error) && error.code === "ENOENT"))
|
|
113741
|
+
throw error;
|
|
113742
|
+
}
|
|
113743
|
+
};
|
|
113744
|
+
|
|
113745
|
+
// packages/omo-opencode/src/cli/service-auth/session.ts
|
|
113746
|
+
import { homedir as homedir33 } from "os";
|
|
113654
113747
|
|
|
113655
113748
|
// packages/omo-opencode/src/cli/service-auth/signed-out-marker.ts
|
|
113656
113749
|
init_zod();
|
|
113657
|
-
import { mkdir as mkdir12, readFile as readFile35, rename as
|
|
113658
|
-
import { dirname as dirname43, join as
|
|
113750
|
+
import { mkdir as mkdir12, readFile as readFile35, rename as rename9, rm as rm17, writeFile as writeFile17 } from "fs/promises";
|
|
113751
|
+
import { dirname as dirname43, join as join110 } from "path";
|
|
113659
113752
|
var markerSchema = object({ device: string2().nullable(), at: string2() });
|
|
113660
|
-
var signedOutMarkerPath = (home, credential) =>
|
|
113753
|
+
var signedOutMarkerPath = (home, credential) => join110(home, ".omo", "account-state", `${credential}.signed-out.json`);
|
|
113661
113754
|
async function readSignedOutMarker(path) {
|
|
113662
113755
|
const text = await readFile35(path, "utf8").catch(() => null);
|
|
113663
113756
|
if (text === null)
|
|
@@ -113675,7 +113768,7 @@ async function writeSignedOutMarker(path, device) {
|
|
|
113675
113768
|
await mkdir12(dirname43(path), { recursive: true, mode: 448 });
|
|
113676
113769
|
const staging = `${path}.${process.pid}.tmp`;
|
|
113677
113770
|
await writeFile17(staging, JSON.stringify({ device, at: new Date().toISOString() }), { mode: 384 });
|
|
113678
|
-
await
|
|
113771
|
+
await rename9(staging, path);
|
|
113679
113772
|
}
|
|
113680
113773
|
var clearSignedOutMarker = (path) => rm17(path, { force: true });
|
|
113681
113774
|
|
|
@@ -113690,11 +113783,18 @@ class SessionEnded extends SignInError {
|
|
|
113690
113783
|
}
|
|
113691
113784
|
}
|
|
113692
113785
|
var DEVICE_REVOKING_REFUSALS = new Set(["account_deleted", "reauth_required", "device_revoked"]);
|
|
113786
|
+
var discardedOf = (credentials, cause) => ({
|
|
113787
|
+
kind: "credential",
|
|
113788
|
+
deviceId: credentials.device.id,
|
|
113789
|
+
accountId: credentials.accountId,
|
|
113790
|
+
owner: credentials.owner,
|
|
113791
|
+
cause
|
|
113792
|
+
});
|
|
113693
113793
|
function createSession(options) {
|
|
113694
113794
|
const api = serviceOrigin(options.api);
|
|
113695
113795
|
const now = options.now ?? Date.now;
|
|
113696
|
-
const { store, signal } = options;
|
|
113697
|
-
const markerPath = signedOutMarkerPath(options.home ??
|
|
113796
|
+
const { store, signal, beforeKeysDiscarded } = options;
|
|
113797
|
+
const markerPath = signedOutMarkerPath(options.home ?? homedir33(), credentialId(api));
|
|
113698
113798
|
async function locked(action) {
|
|
113699
113799
|
signal?.throwIfAborted();
|
|
113700
113800
|
return withCredentialLock(api, async () => {
|
|
@@ -113703,6 +113803,11 @@ function createSession(options) {
|
|
|
113703
113803
|
}, options.home);
|
|
113704
113804
|
}
|
|
113705
113805
|
const request = (path, init) => requestApi(api, path, init, signal);
|
|
113806
|
+
const accountOf = async (access) => {
|
|
113807
|
+
const body = await request("/v1/me", { headers: { authorization: `Bearer ${access}` } }).catch(() => null);
|
|
113808
|
+
const id = typeof body === "object" && body !== null && "account" in body && typeof body.account === "object" && body.account !== null && "id" in body.account ? body.account.id : undefined;
|
|
113809
|
+
return typeof id === "string" && id !== "" ? id : undefined;
|
|
113810
|
+
};
|
|
113706
113811
|
async function refreshed(current) {
|
|
113707
113812
|
if (current.refreshState === "uncertain" || current.refreshAttempt !== undefined) {
|
|
113708
113813
|
throw new SessionEnded(`Refresh recovery can no longer be proved safe. ${signInHint("again")}`, false, "refresh_recovery_expired");
|
|
@@ -113719,6 +113824,7 @@ function createSession(options) {
|
|
|
113719
113824
|
if (error instanceof CredentialStoreError)
|
|
113720
113825
|
throw error;
|
|
113721
113826
|
if (error instanceof ApiRefusal && error.status < 500 && ["unauthorized", "account_deleted", "reauth_required", "invalid_grant", "device_revoked"].includes(error.code)) {
|
|
113827
|
+
await beforeKeysDiscarded(discardedOf(current, "refused"));
|
|
113722
113828
|
await store.clear();
|
|
113723
113829
|
throw new SessionEnded(error.code === "reauth_required" ? `This session was ended because its refresh token was reused. ${signInHint("again")}` : refusalMessage(refusalGuidance(error.code, error.status)), DEVICE_REVOKING_REFUSALS.has(error.code), error.code);
|
|
113724
113830
|
}
|
|
@@ -113744,6 +113850,17 @@ function createSession(options) {
|
|
|
113744
113850
|
},
|
|
113745
113851
|
async save(value) {
|
|
113746
113852
|
await locked(async () => {
|
|
113853
|
+
let stored;
|
|
113854
|
+
try {
|
|
113855
|
+
stored = await store.readAuthoritative();
|
|
113856
|
+
} catch (error) {
|
|
113857
|
+
if (!(error instanceof InvalidCredentialState))
|
|
113858
|
+
throw error;
|
|
113859
|
+
await beforeKeysDiscarded({ kind: "unreadable" });
|
|
113860
|
+
stored = null;
|
|
113861
|
+
}
|
|
113862
|
+
if (stored !== null && stored.device.id !== value.device.id)
|
|
113863
|
+
await beforeKeysDiscarded(discardedOf(stored, "replaced"));
|
|
113747
113864
|
await store.write(value);
|
|
113748
113865
|
await clearSignedOutMarker(markerPath);
|
|
113749
113866
|
});
|
|
@@ -113770,12 +113887,16 @@ function createSession(options) {
|
|
|
113770
113887
|
async logout() {
|
|
113771
113888
|
return locked(async () => {
|
|
113772
113889
|
let current = null;
|
|
113890
|
+
let account;
|
|
113773
113891
|
try {
|
|
113774
113892
|
current = await store.readAuthoritative();
|
|
113775
113893
|
if (current !== null) {
|
|
113776
113894
|
if (current.refreshState === "uncertain")
|
|
113777
113895
|
return false;
|
|
113778
113896
|
const access = Date.parse(current.accessTokenExpiresAt) <= now() ? (await refreshed(current)).accessToken : current.accessToken;
|
|
113897
|
+
if (current.accountId === undefined && current.owner === undefined && await beforeKeysDiscarded.wantsAccount?.() === true) {
|
|
113898
|
+
account = await accountOf(access);
|
|
113899
|
+
}
|
|
113779
113900
|
await request(`/v1/devices/${encodeURIComponent(current.device.id)}`, {
|
|
113780
113901
|
method: "DELETE",
|
|
113781
113902
|
headers: { authorization: `Bearer ${access}` }
|
|
@@ -113790,6 +113911,9 @@ function createSession(options) {
|
|
|
113790
113911
|
throw error;
|
|
113791
113912
|
} finally {
|
|
113792
113913
|
await writeSignedOutMarker(markerPath, current?.device.id ?? null);
|
|
113914
|
+
const stored = current === null ? null : await store.read().catch(() => current);
|
|
113915
|
+
if (stored !== null)
|
|
113916
|
+
await beforeKeysDiscarded(discardedOf(stored.accountId === undefined && account !== undefined ? { ...stored, accountId: account } : stored, "logout"));
|
|
113793
113917
|
await store.clear();
|
|
113794
113918
|
}
|
|
113795
113919
|
});
|
|
@@ -113826,6 +113950,26 @@ function createSession(options) {
|
|
|
113826
113950
|
};
|
|
113827
113951
|
}
|
|
113828
113952
|
|
|
113953
|
+
// packages/omo-opencode/src/cli/service-auth/sync-pin-retire.ts
|
|
113954
|
+
var reason = (error) => error instanceof Error && ("code" in error) && typeof error.code === "string" ? error.code : "unknown";
|
|
113955
|
+
function retireSyncPinOnDiscard(options) {
|
|
113956
|
+
const hook = async (discarded) => {
|
|
113957
|
+
if (discarded.kind === "unreadable") {
|
|
113958
|
+
options.log("memory sync: a stored sign-in could not be read while it was replaced; its sync pin was left in place");
|
|
113959
|
+
return;
|
|
113960
|
+
}
|
|
113961
|
+
const account = discarded.owner?.accountId ?? discarded.accountId;
|
|
113962
|
+
if (account === undefined)
|
|
113963
|
+
return;
|
|
113964
|
+
try {
|
|
113965
|
+
await retireSyncDevice({ pinDir: options.pinDir(), account });
|
|
113966
|
+
} catch (error) {
|
|
113967
|
+
options.log(`memory sync: the sync pin could not be retired (${reason(error)}); it was left in place`);
|
|
113968
|
+
}
|
|
113969
|
+
};
|
|
113970
|
+
return Object.assign(hook, { wantsAccount: () => hasLiveTrustAnchor(options.pinDir()).catch(() => false) });
|
|
113971
|
+
}
|
|
113972
|
+
|
|
113829
113973
|
// packages/omo-opencode/src/cli/service-auth/commands.ts
|
|
113830
113974
|
async function ensureServiceAvailable(session, api) {
|
|
113831
113975
|
try {
|
|
@@ -113868,7 +114012,12 @@ async function run2(action, options) {
|
|
|
113868
114012
|
try {
|
|
113869
114013
|
const api = serviceOrigin(options.api ?? process.env.OMO_SERVICE_API_URL ?? "https://api.omo.dev");
|
|
113870
114014
|
const store = createCredentialStore(api, { wait: INTERACTIVE_READ_WAIT });
|
|
113871
|
-
const session = createSession({
|
|
114015
|
+
const session = createSession({
|
|
114016
|
+
api,
|
|
114017
|
+
store,
|
|
114018
|
+
signal: controller.signal,
|
|
114019
|
+
beforeKeysDiscarded: retireSyncPinOnDiscard({ pinDir: () => syncPinDir(resolveMemoryRoot(process.env, process.cwd())), log: (line) => console.error(line) })
|
|
114020
|
+
});
|
|
113872
114021
|
if (action === "logout") {
|
|
113873
114022
|
const revoked = await session.logout();
|
|
113874
114023
|
console.log("Signed out of OmO. Stored credentials and device keys were removed.");
|
|
@@ -114136,11 +114285,11 @@ async function boulder(options) {
|
|
|
114136
114285
|
// packages/omo-opencode/src/cli/codex-ulw-loop.ts
|
|
114137
114286
|
import { spawn as spawn6 } from "child_process";
|
|
114138
114287
|
import { existsSync as existsSync67, readFileSync as readFileSync45, realpathSync as realpathSync14 } from "fs";
|
|
114139
|
-
import { homedir as
|
|
114288
|
+
import { homedir as homedir34 } from "os";
|
|
114140
114289
|
var ULW_LOOP_DELEGATION_SENTINEL = "OMO_ULW_LOOP_DELEGATED";
|
|
114141
114290
|
function resolveCodexUlwLoopCommand(input = {}) {
|
|
114142
114291
|
const env = input.env ?? process.env;
|
|
114143
|
-
const homeDir = input.homeDir ??
|
|
114292
|
+
const homeDir = input.homeDir ?? homedir34();
|
|
114144
114293
|
const localComponentBin = resolveLocalUlwLoopBin(env, homeDir);
|
|
114145
114294
|
if (localComponentBin !== null)
|
|
114146
114295
|
return { executable: localComponentBin, argsPrefix: [] };
|
|
@@ -2,4 +2,5 @@ export { credentialLockPaths, withCredentialLock } from "./credential-lock";
|
|
|
2
2
|
export { currentServiceDevice } from "./protocol";
|
|
3
3
|
export { CredentialIdentityChanged, type CredentialStore, createCredentialStore, KeychainApprovalPendingError, quietNotice } from "./keystore";
|
|
4
4
|
export { type Credentials, SignInError, serviceOrigin } from "./protocol";
|
|
5
|
-
export { createSession, type Session } from "./session";
|
|
5
|
+
export { type BeforeKeysDiscarded, createSession, type DiscardedCredential, type Session } from "./session";
|
|
6
|
+
export { retireSyncPinOnDiscard } from "./sync-pin-retire";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CredentialOwner } from "./credential-owner";
|
|
1
2
|
import { type CredentialStore } from "./keystore";
|
|
2
3
|
import { type ChooseDevice, type Credentials, SignInError } from "./protocol";
|
|
3
4
|
export declare class SessionEnded extends SignInError {
|
|
@@ -5,12 +6,33 @@ export declare class SessionEnded extends SignInError {
|
|
|
5
6
|
readonly code: string;
|
|
6
7
|
constructor(message: string, deviceRevoked: boolean, code: string);
|
|
7
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* A stored principal whose private keys are about to be discarded (#12280), or a stored item that
|
|
11
|
+
* could not be read when a save replaced it. The hook retires that principal's memory-sync pin; it
|
|
12
|
+
* never throws, so a failure to retire never blocks the discard.
|
|
13
|
+
*/
|
|
14
|
+
export type DiscardedCredential = {
|
|
15
|
+
readonly kind: "credential";
|
|
16
|
+
readonly deviceId: string;
|
|
17
|
+
readonly accountId: string | undefined;
|
|
18
|
+
readonly owner: CredentialOwner | undefined;
|
|
19
|
+
readonly cause: "refused" | "forget" | "logout" | "replaced";
|
|
20
|
+
} | {
|
|
21
|
+
readonly kind: "unreadable";
|
|
22
|
+
};
|
|
23
|
+
export type BeforeKeysDiscarded = ((discarded: DiscardedCredential) => Promise<void>) & {
|
|
24
|
+
/** Whether a sign-in that names no account should have it read before logout revokes the device. */
|
|
25
|
+
readonly wantsAccount?: () => Promise<boolean>;
|
|
26
|
+
};
|
|
27
|
+
export declare const discardedOf: (credentials: Credentials, cause: "refused" | "forget" | "logout" | "replaced") => DiscardedCredential;
|
|
8
28
|
export declare function createSession(options: {
|
|
9
29
|
readonly api: string;
|
|
10
30
|
readonly store: CredentialStore;
|
|
11
31
|
readonly home?: string;
|
|
12
32
|
readonly signal?: AbortSignal;
|
|
13
33
|
readonly now?: () => number;
|
|
34
|
+
/** Runs inside the credential lock immediately before a stored principal's keys are discarded. */
|
|
35
|
+
readonly beforeKeysDiscarded: BeforeKeysDiscarded;
|
|
14
36
|
}): {
|
|
15
37
|
request: (path: string, init: RequestInit) => Promise<unknown>;
|
|
16
38
|
signal: AbortSignal | undefined;
|
|
@@ -26,6 +48,11 @@ export declare function createSession(options: {
|
|
|
26
48
|
update<T>(action: (current: Credentials | null) => Promise<T>, options?: {
|
|
27
49
|
readonly replaceInvalid?: boolean;
|
|
28
50
|
}): Promise<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Deletes the item without reading it (a corrupt or locked item must still be removable, with one
|
|
53
|
+
* native call), so it cannot name the account whose pin to retire: `omo account forget --device`
|
|
54
|
+
* and `logout` read first and retire; this one leaves the pin (a stale pin is harmless for keys).
|
|
55
|
+
*/
|
|
29
56
|
forget(): Promise<void>;
|
|
30
57
|
accessSnapshot: () => Promise<Credentials | null>;
|
|
31
58
|
logout(): Promise<boolean>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BeforeKeysDiscarded } from "./session";
|
|
2
|
+
export declare function retireSyncPinOnDiscard(options: {
|
|
3
|
+
/** The trust-pin directory of the memory root the caller already resolves. */
|
|
4
|
+
readonly pinDir: () => string;
|
|
5
|
+
/** The caller's own logger; one line per pin it could not retire. */
|
|
6
|
+
readonly log: (line: string) => void;
|
|
7
|
+
}): BeforeKeysDiscarded;
|