@rse/ase 1.0.7 → 2.0.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/dst/ase-agent-definition-api.d.ts +184 -0
- package/dst/ase-agent-definition-api.js +6 -0
- package/dst/ase-agent-definition-builtin/condenser.js +42 -0
- package/dst/ase-agent-definition-builtin/editor.js +45 -0
- package/dst/ase-agent-definition-builtin/estimator.js +98 -0
- package/dst/ase-agent-definition-builtin/implementer.js +121 -0
- package/dst/ase-agent-definition-builtin/integrator.js +56 -0
- package/dst/ase-agent-definition-builtin/qualifier.js +61 -0
- package/dst/ase-agent-definition-builtin/rebooter.js +41 -0
- package/dst/ase-agent-definition-builtin/researcher.js +77 -0
- package/dst/ase-agent-definition-core.js +827 -0
- package/dst/ase-agent-fleet.js +772 -0
- package/dst/ase-agent-process.js +232 -0
- package/dst/ase-agent-relay-client.js +509 -0
- package/dst/ase-agent-relay-core.js +213 -0
- package/dst/ase-agent-relay-server-bind.js +242 -0
- package/dst/ase-agent-relay-server-cli.js +50 -0
- package/dst/ase-agent-runtime-claim.js +189 -0
- package/dst/ase-agent-runtime-engine.js +1100 -0
- package/dst/ase-agent-runtime-exec.js +275 -0
- package/dst/ase-agent-runtime-phase.js +581 -0
- package/dst/ase-agent-runtime-request.js +272 -0
- package/dst/ase-agent-runtime-tool.js +207 -0
- package/dst/ase-agent-runtime.js +1316 -0
- package/dst/ase-agent.js +65 -0
- package/dst/ase-artifact.js +6 -5
- package/dst/ase-config-core.js +465 -0
- package/dst/ase-config-schema.js +351 -0
- package/dst/ase-config-scope.js +172 -0
- package/dst/ase-config.js +25 -585
- package/dst/ase-hook.js +228 -111
- package/dst/ase-lib-daemon-cli.js +130 -0
- package/dst/ase-lib-hash.js +20 -0
- package/dst/{ase-log.js → ase-lib-log.js} +40 -7
- package/dst/ase-lib-server-bind.js +115 -0
- package/dst/ase-lib-server-cli.js +474 -0
- package/dst/{ase-table.js → ase-lib-table.js} +1 -1
- package/dst/{ase-version.js → ase-lib-version.js} +3 -0
- package/dst/ase-man.js +96 -0
- package/dst/ase-mcp.js +166 -13
- package/dst/{ase-getopt.js → ase-service-getopt.js} +82 -80
- package/dst/{ase-markdown.js → ase-service-markdown.js} +18 -11
- package/dst/ase-service-otel.js +1246 -0
- package/dst/{ase-skills.js → ase-service-skills.js} +29 -64
- package/dst/ase-service-state.js +101 -0
- package/dst/ase-service.js +251 -76
- package/dst/ase-setup-common.js +141 -0
- package/dst/ase-setup-mcp.js +359 -0
- package/dst/ase-setup-settings.js +837 -0
- package/dst/ase-setup.js +113 -869
- package/dst/ase-spec.js +31 -19
- package/dst/ase-statusline.js +108 -43
- package/dst/ase-task-board-core.js +739 -0
- package/dst/ase-task-board-filter.js +127 -0
- package/dst/ase-task-board-flow.js +237 -0
- package/dst/ase-task-board-graph.js +497 -0
- package/dst/ase-task-board-stats.js +263 -0
- package/dst/ase-task-board-tui-control.js +775 -0
- package/dst/ase-task-board-tui-model.js +1008 -0
- package/dst/ase-task-board-tui-popup.js +626 -0
- package/dst/ase-task-board-tui-style.js +106 -0
- package/dst/ase-task-board-tui-view.js +847 -0
- package/dst/ase-task-board-tui.js +189 -0
- package/dst/ase-task-board-web-client.css +1 -0
- package/dst/ase-task-board-web-client.html +20 -0
- package/dst/ase-task-board-web-client.js +81 -0
- package/dst/ase-task-board-web-server.js +823 -0
- package/dst/ase-task-board.js +134 -0
- package/dst/ase-task-format.js +757 -0
- package/dst/ase-task-request.js +208 -0
- package/dst/ase-task-store-client.js +495 -0
- package/dst/ase-task-store-core.js +804 -0
- package/dst/ase-task-store-issues.js +237 -0
- package/dst/ase-task-store-plugin-api.js +6 -0
- package/dst/ase-task-store-plugin-ase.js +484 -0
- package/dst/ase-task-store-plugin-delegate.js +137 -0
- package/dst/ase-task-store-plugin-gitea.js +666 -0
- package/dst/ase-task-store-plugin-github.js +696 -0
- package/dst/ase-task-store-plugin-gitlab.js +668 -0
- package/dst/ase-task-store-server-bind.js +538 -0
- package/dst/ase-task-store-server-cli.js +154 -0
- package/dst/ase-task.js +1335 -357
- package/dst/{ase-compat.js → ase-util-compat.js} +2 -2
- package/dst/{ase-diagram.js → ase-util-diagram.js} +107 -32
- package/dst/{ase-meta.js → ase-util-meta.js} +2 -2
- package/dst/{ase-metric.js → ase-util-metric.js} +2 -2
- package/dst/{ase-mint.js → ase-util-mint.js} +19 -12
- package/dst/{ase-worktree.js → ase-util-worktree.js} +30 -19
- package/dst/ase-util.js +20 -0
- package/dst/ase.js +108 -32
- package/dst/man/ase-agent-adhoc.1 +515 -0
- package/dst/man/ase-agent-condenser.1 +193 -0
- package/dst/man/ase-agent-editor.1 +212 -0
- package/dst/man/ase-agent-estimator.1 +214 -0
- package/dst/man/ase-agent-fleet.1 +185 -0
- package/dst/man/ase-agent-implementer.1 +233 -0
- package/dst/man/ase-agent-integrator.1 +213 -0
- package/dst/man/ase-agent-qualifier.1 +214 -0
- package/dst/man/ase-agent-rebooter.1 +193 -0
- package/dst/man/ase-agent-relay.1 +128 -0
- package/dst/man/ase-agent-researcher.1 +217 -0
- package/dst/man/ase-agent.1 +264 -0
- package/dst/man/ase-artifact-list.1 +38 -0
- package/dst/man/ase-artifact-name.1 +39 -0
- package/dst/man/ase-artifact.1 +56 -0
- package/dst/man/ase-config-delete.1 +45 -0
- package/dst/man/ase-config-edit.1 +48 -0
- package/dst/man/ase-config-get.1 +46 -0
- package/dst/man/ase-config-init.1 +60 -0
- package/dst/man/ase-config-list.1 +42 -0
- package/dst/man/ase-config-set.1 +52 -0
- package/dst/man/ase-config.1 +225 -0
- package/dst/man/ase-hook-permission-request.1 +36 -0
- package/dst/man/ase-hook-pre-tool-use.1 +59 -0
- package/dst/man/ase-hook-session-end.1 +47 -0
- package/dst/man/ase-hook-session-persona.1 +37 -0
- package/dst/man/ase-hook-session-start.1 +81 -0
- package/dst/man/ase-hook-stop.1 +34 -0
- package/dst/man/ase-hook-user-prompt-submit.1 +34 -0
- package/dst/man/ase-hook.1 +51 -0
- package/dst/man/ase-man.1 +67 -0
- package/dst/man/ase-mcp.1 +61 -0
- package/dst/man/ase-service-log.1 +43 -0
- package/dst/man/ase-service-send.1 +47 -0
- package/dst/man/ase-service-start.1 +54 -0
- package/dst/man/ase-service-status.1 +46 -0
- package/dst/man/ase-service-stop.1 +37 -0
- package/dst/man/ase-service.1 +85 -0
- package/dst/man/ase-setup-disable.1 +44 -0
- package/dst/man/ase-setup-enable.1 +45 -0
- package/dst/man/ase-setup-install.1 +73 -0
- package/dst/man/ase-setup-mcp.1 +124 -0
- package/dst/man/ase-setup-status.1 +60 -0
- package/dst/man/ase-setup-statusline.1 +92 -0
- package/dst/man/ase-setup-telemetry.1 +92 -0
- package/dst/man/ase-setup-uninstall.1 +59 -0
- package/dst/man/ase-setup-update.1 +64 -0
- package/dst/man/ase-setup.1 +93 -0
- package/dst/man/ase-spec-export.1 +62 -0
- package/dst/man/ase-spec-lint.1 +40 -0
- package/dst/man/ase-spec-preview.1 +40 -0
- package/dst/man/ase-spec.1 +46 -0
- package/dst/man/ase-statusline.1 +189 -0
- package/dst/man/ase-task-assign.1 +71 -0
- package/dst/man/ase-task-board.1 +384 -0
- package/dst/man/ase-task-delete.1 +35 -0
- package/dst/man/ase-task-edit.1 +46 -0
- package/dst/man/ase-task-idscheme.1 +65 -0
- package/dst/man/ase-task-lifecycle.1 +57 -0
- package/dst/man/ase-task-list.1 +47 -0
- package/dst/man/ase-task-load.1 +36 -0
- package/dst/man/ase-task-newid.1 +61 -0
- package/dst/man/ase-task-purge.1 +37 -0
- package/dst/man/ase-task-rename.1 +44 -0
- package/dst/man/ase-task-request.1 +61 -0
- package/dst/man/ase-task-save.1 +48 -0
- package/dst/man/ase-task-status.1 +55 -0
- package/dst/man/ase-task-store.1 +194 -0
- package/dst/man/ase-task-view.1 +40 -0
- package/dst/man/ase-task.1 +160 -0
- package/dst/man/ase-util-compat.1 +25 -0
- package/dst/man/ase-util-diagram.1 +76 -0
- package/dst/man/ase-util-meta.1 +45 -0
- package/dst/man/ase-util-metric.1 +54 -0
- package/dst/man/ase-util-mint.1 +59 -0
- package/dst/man/ase-util-worktree.1 +72 -0
- package/dst/man/ase-util.1 +50 -0
- package/dst/man/ase.1 +124 -0
- package/package.json +79 -21
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/agents/ase-meta-diagram.md +12 -8
- package/plugin/agents/ase-repo-review.md +322 -0
- package/plugin/hooks/hooks-codex.json +5 -0
- package/plugin/hooks/hooks-copilot.json +5 -0
- package/plugin/hooks/hooks.json +8 -0
- package/plugin/meta/ase-common-approach.md +117 -0
- package/plugin/meta/ase-common-changeset.md +256 -0
- package/plugin/meta/ase-common-code.md +10 -173
- package/plugin/meta/ase-common-grill.md +317 -0
- package/plugin/meta/ase-common-resolve.md +305 -0
- package/plugin/meta/ase-common-task.md +83 -4
- package/plugin/meta/ase-constitution.md +0 -2
- package/plugin/meta/ase-format-specbook.md +208 -25
- package/plugin/meta/ase-format-specbook.yaml +242 -851
- package/plugin/meta/ase-format-task.md +669 -125
- package/plugin/meta/ase-persona.md +3 -4
- package/plugin/meta/ase-skill.md +9 -0
- package/plugin/mods/ase-mods.ts +409 -0
- package/plugin/mods/claude-code.d.ts +13417 -0
- package/plugin/skills/ase-arch-analyze/SKILL.md +1 -1
- package/plugin/skills/ase-arch-analyze/help.md +2 -2
- package/plugin/skills/ase-code-analyze/SKILL.md +59 -8
- package/plugin/skills/ase-code-analyze/help.md +29 -4
- package/plugin/skills/ase-code-edit/SKILL.md +107 -181
- package/plugin/skills/ase-code-edit/help.md +118 -31
- package/plugin/skills/ase-code-lint/SKILL.md +64 -13
- package/plugin/skills/ase-code-lint/help.md +32 -2
- package/plugin/skills/ase-docs-proofread/SKILL.md +4 -4
- package/plugin/skills/ase-docs-proofread/help.md +1 -1
- package/plugin/skills/ase-docs-refine/SKILL.md +4 -4
- package/plugin/skills/ase-docs-shorten/SKILL.md +4 -4
- package/plugin/skills/ase-help-intent/data.md +2164 -1087
- package/plugin/skills/ase-help-intent/help.md +1 -1
- package/plugin/skills/ase-help-skill/catalog.md +12 -9
- package/plugin/skills/ase-meta-brainstorm/SKILL.md +1 -1
- package/plugin/skills/ase-meta-config/SKILL.md +3 -4
- package/plugin/skills/ase-meta-config/help.md +31 -10
- package/plugin/skills/ase-meta-mint/SKILL.md +5 -5
- package/plugin/skills/ase-meta-mint/help.md +10 -5
- package/plugin/skills/ase-meta-why/help.md +1 -1
- package/plugin/skills/ase-meta-workflow/SKILL.md +7 -7
- package/plugin/skills/ase-meta-workflow/help.md +4 -4
- package/plugin/skills/ase-meta-workflow/sample.md +3 -3
- package/plugin/skills/ase-meta-workflow/workflow.txt +22 -18
- package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/SKILL.md +4 -3
- package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/help.md +5 -5
- package/plugin/skills/{ase-meta-commit → ase-repo-commit}/SKILL.md +6 -6
- package/plugin/skills/{ase-meta-commit → ase-repo-commit}/help.md +5 -5
- package/plugin/skills/{ase-meta-diff → ase-repo-diff}/SKILL.md +6 -6
- package/plugin/skills/{ase-meta-diff → ase-repo-diff}/help.md +8 -8
- package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/SKILL.md +19 -19
- package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/help.md +10 -12
- package/plugin/skills/ase-repo-merge/SKILL.md +346 -0
- package/plugin/skills/ase-repo-merge/help.md +107 -0
- package/plugin/skills/ase-repo-resolve/SKILL.md +158 -0
- package/plugin/skills/ase-repo-resolve/help.md +102 -0
- package/plugin/skills/ase-repo-review/SKILL.md +406 -0
- package/plugin/skills/ase-repo-review/help.md +181 -0
- package/plugin/skills/ase-spec-edit/SKILL.md +117 -183
- package/plugin/skills/ase-spec-edit/help.md +107 -26
- package/plugin/skills/ase-sync-reconcile/help.md +1 -1
- package/plugin/skills/ase-task-assign/SKILL.md +111 -0
- package/plugin/skills/ase-task-assign/help.md +119 -0
- package/plugin/skills/ase-task-condense/SKILL.md +21 -21
- package/plugin/skills/ase-task-condense/help.md +12 -10
- package/plugin/skills/ase-task-delete/SKILL.md +1 -1
- package/plugin/skills/ase-task-dissect/SKILL.md +71 -48
- package/plugin/skills/ase-task-dissect/help.md +10 -9
- package/plugin/skills/ase-task-edit/SKILL.md +379 -94
- package/plugin/skills/ase-task-edit/help.md +95 -22
- package/plugin/skills/ase-task-estimate/SKILL.md +492 -0
- package/plugin/skills/ase-task-estimate/help.md +158 -0
- package/plugin/skills/ase-task-grill/SKILL.md +246 -138
- package/plugin/skills/ase-task-grill/help.md +129 -26
- package/plugin/skills/ase-task-id/SKILL.md +8 -1
- package/plugin/skills/ase-task-id/help.md +6 -3
- package/plugin/skills/ase-task-implement/SKILL.md +535 -145
- package/plugin/skills/ase-task-implement/help.md +138 -47
- package/plugin/skills/ase-task-integrate/SKILL.md +549 -0
- package/plugin/skills/ase-task-integrate/help.md +187 -0
- package/plugin/skills/ase-task-list/SKILL.md +55 -23
- package/plugin/skills/ase-task-list/help.md +45 -21
- package/plugin/skills/ase-task-reboot/SKILL.md +84 -43
- package/plugin/skills/ase-task-reboot/help.md +28 -8
- package/plugin/skills/ase-task-rename/SKILL.md +10 -2
- package/plugin/skills/ase-task-research/SKILL.md +386 -0
- package/plugin/skills/ase-task-research/help.md +102 -0
- package/plugin/skills/ase-task-status/SKILL.md +137 -0
- package/plugin/skills/ase-task-status/help.md +80 -0
- package/plugin/skills/ase-task-view/SKILL.md +49 -24
- package/plugin/skills/ase-task-view/help.md +19 -9
- package/plugin/agents/ase-meta-review.md +0 -187
- package/plugin/skills/ase-code-craft/SKILL.md +0 -264
- package/plugin/skills/ase-code-craft/help.md +0 -122
- package/plugin/skills/ase-code-refactor/SKILL.md +0 -232
- package/plugin/skills/ase-code-refactor/help.md +0 -109
- package/plugin/skills/ase-code-resolve/SKILL.md +0 -289
- package/plugin/skills/ase-code-resolve/help.md +0 -116
- package/plugin/skills/ase-meta-review/SKILL.md +0 -210
- package/plugin/skills/ase-meta-review/help.md +0 -96
- package/plugin/skills/ase-task-preflight/SKILL.md +0 -166
- package/plugin/skills/ase-task-preflight/help.md +0 -82
- /package/dst/{ase-ignore.js → ase-lib-ignore.js} +0 -0
- /package/dst/{ase-stdio.js → ase-lib-stdio.js} +0 -0
- /package/dst/{ase-kv.js → ase-service-kv.js} +0 -0
- /package/dst/{ase-sleep.js → ase-service-sleep.js} +0 -0
- /package/dst/{ase-timestamp.js → ase-service-timestamp.js} +0 -0
package/dst/ase-spec.js
CHANGED
|
@@ -8,16 +8,23 @@ import fs from "node:fs";
|
|
|
8
8
|
import { isScalar } from "yaml";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import sourceCodeError from "source-code-error";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { renderDiagnostic } from "@rse/specbook/dst/specbook-diagnostic.js";
|
|
12
|
+
import { renderVerbose } from "@rse/specbook/dst/specbook-verbose.js";
|
|
13
|
+
import { Config } from "./ase-config-core.js";
|
|
14
|
+
import { configSchema } from "./ase-config-schema.js";
|
|
13
15
|
import { Task } from "./ase-task.js";
|
|
14
16
|
import { Artifact } from "./ase-artifact.js";
|
|
15
|
-
import { Meta } from "./ase-meta.js";
|
|
16
|
-
import { writeStdout } from "./ase-stdio.js";
|
|
17
|
+
import { Meta } from "./ase-util-meta.js";
|
|
18
|
+
import { writeStdout } from "./ase-lib-stdio.js";
|
|
17
19
|
/* reusable functionality: lint, export, and preview the SpecBook-based
|
|
18
20
|
project specification, located via the "project.artifact.spec.basedir"
|
|
19
21
|
and "project.artifact.spec.schema" configuration */
|
|
20
22
|
export class Spec {
|
|
23
|
+
/* the SpecBook export formats, mirrored here (and checked for completeness
|
|
24
|
+
against SpecBook at compile-time) to not load SpecBook for the MCP schema */
|
|
25
|
+
static formats = Object.keys({
|
|
26
|
+
json: true, json5: true, yaml: true, toon: true, html: true, pdf: true, md: true
|
|
27
|
+
});
|
|
21
28
|
/* resolve the YAML schema configuration files: the whitespace-separated
|
|
22
29
|
entries of the configured "project.artifact.spec.schema", merged in
|
|
23
30
|
the given order, where each entry is either the literal "std" for the
|
|
@@ -51,8 +58,10 @@ export class Spec {
|
|
|
51
58
|
/* create the SpecBook API instance, routing its verbose processing
|
|
52
59
|
messages into the log according to their verbosity level, while
|
|
53
60
|
its "none" level messages, for consumers which never see the log,
|
|
54
|
-
additionally reach the given collector
|
|
55
|
-
|
|
61
|
+
additionally reach the given collector
|
|
62
|
+
(SpecBook itself is loaded on first use only) */
|
|
63
|
+
static async api(log, notices) {
|
|
64
|
+
const { SpecBook } = await import("@rse/specbook");
|
|
56
65
|
return new SpecBook({
|
|
57
66
|
verbose: (cmd, msg, level) => {
|
|
58
67
|
const text = renderVerbose(msg);
|
|
@@ -93,11 +102,11 @@ export class Spec {
|
|
|
93
102
|
/* lint the specification Markdown files below the "spec" artifact
|
|
94
103
|
base directory against the schema configuration */
|
|
95
104
|
static async lint(log) {
|
|
96
|
-
const result = await Spec.unmarked(Spec.api(log).lint({
|
|
105
|
+
const result = await Spec.unmarked(Spec.api(log).then((api) => api.lint({
|
|
97
106
|
config: Spec.configFiles(log),
|
|
98
107
|
basedir: Artifact.basedir(log, "spec"),
|
|
99
108
|
gitignore: Spec.gitignore
|
|
100
|
-
}));
|
|
109
|
+
})));
|
|
101
110
|
return result.diagnostics.map((d) => ({ ...d, file: Spec.relativize(d.file) }));
|
|
102
111
|
}
|
|
103
112
|
/* render a diagnostic as a multi-line message with the affected
|
|
@@ -128,38 +137,38 @@ export class Spec {
|
|
|
128
137
|
base directory into the requested formats, one buffer per format,
|
|
129
138
|
collecting the emitted environment notices if requested */
|
|
130
139
|
static export(log, formats, notices) {
|
|
131
|
-
return Spec.unmarked(Spec.api(log, notices).export({
|
|
140
|
+
return Spec.unmarked(Spec.api(log, notices).then((api) => api.export({
|
|
132
141
|
config: Spec.configFiles(log),
|
|
133
142
|
basedir: Artifact.basedir(log, "spec"),
|
|
134
143
|
gitignore: Spec.gitignore,
|
|
135
144
|
formats
|
|
136
|
-
}));
|
|
145
|
+
})));
|
|
137
146
|
}
|
|
138
147
|
/* export the specification like "export" and then keep the export
|
|
139
148
|
in sync with its sources, handing every fresh set of buffers to
|
|
140
149
|
"onExport", where "outputs" names the files "onExport" writes,
|
|
141
150
|
so an output which is itself an observed source can be refused */
|
|
142
151
|
static watch(log, formats, outputs, onExport) {
|
|
143
|
-
return Spec.unmarked(Spec.api(log).watch({
|
|
152
|
+
return Spec.unmarked(Spec.api(log).then((api) => api.watch({
|
|
144
153
|
config: Spec.configFiles(log),
|
|
145
154
|
basedir: Artifact.basedir(log, "spec"),
|
|
146
155
|
gitignore: Spec.gitignore,
|
|
147
156
|
formats,
|
|
148
157
|
outputs,
|
|
149
158
|
onExport
|
|
150
|
-
}));
|
|
159
|
+
})));
|
|
151
160
|
}
|
|
152
161
|
/* serve the HTML export of the specification as a live preview,
|
|
153
162
|
kept in sync with its sources and pushed into the connected
|
|
154
163
|
browsers as an in-place document update */
|
|
155
164
|
static preview(log, addr, port) {
|
|
156
|
-
return Spec.unmarked(Spec.api(log).preview({
|
|
165
|
+
return Spec.unmarked(Spec.api(log).then((api) => api.preview({
|
|
157
166
|
config: Spec.configFiles(log),
|
|
158
167
|
basedir: Artifact.basedir(log, "spec"),
|
|
159
168
|
gitignore: Spec.gitignore,
|
|
160
169
|
addr,
|
|
161
170
|
port
|
|
162
|
-
}));
|
|
171
|
+
})));
|
|
163
172
|
}
|
|
164
173
|
}
|
|
165
174
|
/* CLI command "ase spec" */
|
|
@@ -201,6 +210,7 @@ export default class SpecCommand {
|
|
|
201
210
|
"(default: \"index.html\" inside the specification base directory)", (value, previous) => previous.concat(value), new Array())
|
|
202
211
|
.option("-w, --watch", "keep the outputs in sync by re-exporting on every source change")
|
|
203
212
|
.action(async (opts) => {
|
|
213
|
+
const { parseOutputSpec } = await import("@rse/specbook");
|
|
204
214
|
const outputs = (opts.output.length > 0 ? opts.output :
|
|
205
215
|
[path.join(Artifact.basedir(this.log, "spec"), "index.html")]).map(parseOutputSpec);
|
|
206
216
|
/* a re-export has to land somewhere it can be picked up again,
|
|
@@ -232,13 +242,14 @@ export default class SpecCommand {
|
|
|
232
242
|
spec
|
|
233
243
|
.command("preview")
|
|
234
244
|
.description("Serve the HTML export of the specification Markdown files as a live preview")
|
|
235
|
-
.option("-a, --addr <ip-addr>", "IP address to listen on
|
|
236
|
-
.option("-p, --port <tcp-port>", "TCP port to listen on
|
|
245
|
+
.option("-a, --addr <ip-addr>", "IP address to listen on (default: SpecBook preview address)")
|
|
246
|
+
.option("-p, --port <tcp-port>", "TCP port to listen on (default: SpecBook preview port)")
|
|
237
247
|
.action(async (opts) => {
|
|
238
|
-
const
|
|
248
|
+
const { previewAddr, previewPort } = await import("@rse/specbook");
|
|
249
|
+
const port = Number(opts.port ?? previewPort);
|
|
239
250
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
240
251
|
throw new Error(`invalid TCP port "${opts.port}"`);
|
|
241
|
-
await Spec.preview(this.log, opts.addr, port);
|
|
252
|
+
await Spec.preview(this.log, opts.addr ?? previewAddr, port);
|
|
242
253
|
await new Promise(() => { });
|
|
243
254
|
});
|
|
244
255
|
}
|
|
@@ -314,7 +325,7 @@ export class SpecMCP {
|
|
|
314
325
|
"(like a PDF rendering falling back onto a system-installed browser), which are " +
|
|
315
326
|
"worth reporting to the user verbatim.",
|
|
316
327
|
inputSchema: {
|
|
317
|
-
format: z.enum(formats).optional()
|
|
328
|
+
format: z.enum(Spec.formats).optional()
|
|
318
329
|
.describe("output format (default: inferred from the `output` file extension, else `json`)"),
|
|
319
330
|
output: z.string().optional()
|
|
320
331
|
.describe("output file path (\"-\" or omitted returns the result directly)")
|
|
@@ -326,6 +337,7 @@ export class SpecMCP {
|
|
|
326
337
|
}, async (args) => {
|
|
327
338
|
const notices = new Array();
|
|
328
339
|
try {
|
|
340
|
+
const { parseOutputSpec } = await import("@rse/specbook");
|
|
329
341
|
/* an explicit format takes the output as a plain file path, while
|
|
330
342
|
otherwise the output is an "[<format>:]<file>" specification */
|
|
331
343
|
const spec = args.format !== undefined || args.output === undefined ?
|
package/dst/ase-statusline.js
CHANGED
|
@@ -10,8 +10,10 @@ import { execFileSync } from "node:child_process";
|
|
|
10
10
|
import { InvalidArgumentError } from "commander";
|
|
11
11
|
import { execaSync } from "execa";
|
|
12
12
|
import { Chalk } from "chalk";
|
|
13
|
-
import { Config,
|
|
14
|
-
import {
|
|
13
|
+
import { Config, sessionState } from "./ase-config-core.js";
|
|
14
|
+
import { configSchema } from "./ase-config-schema.js";
|
|
15
|
+
import { parseScope, userStateDir, projectIdOf } from "./ase-config-scope.js";
|
|
16
|
+
import { readStdin, writeStdout } from "./ase-lib-stdio.js";
|
|
15
17
|
import pkg from "../package.json" with { type: "json" };
|
|
16
18
|
/* forced-color chalk instance: stdout is a pipe under Anthropic Claude Code CLI,
|
|
17
19
|
so chalk auto-detection would yield level 0; force level 1 to keep
|
|
@@ -181,6 +183,69 @@ const memoize = (fn) => {
|
|
|
181
183
|
let cache = null;
|
|
182
184
|
return () => (cache ??= { value: fn() }).value;
|
|
183
185
|
};
|
|
186
|
+
/* the ChatGPT backend endpoint providing the OpenAI Codex subscription usage */
|
|
187
|
+
const CODEX_USAGE = "https://chatgpt.com/backend-api/wham/usage";
|
|
188
|
+
/* time-to-live (in milliseconds) of the cached OpenAI Codex subscription usage */
|
|
189
|
+
const CODEX_USAGE_TTL = 60 * 1000;
|
|
190
|
+
/* fetch the rate-limit windows directly from the ChatGPT backend with the credential
|
|
191
|
+
stored by the OpenAI Codex CLI; the result (even a failed one) is cached for a short
|
|
192
|
+
time, as the statusline is rendered frequently, and no failure is ever raised */
|
|
193
|
+
const fetchCodexLimits = async () => {
|
|
194
|
+
/* reuse the cached result while it is still fresh */
|
|
195
|
+
const cacheFile = path.join(userStateDir(), "statusline-codex-usage.json");
|
|
196
|
+
let cache = {};
|
|
197
|
+
try {
|
|
198
|
+
cache = (JSON.parse(fs.readFileSync(cacheFile, "utf8")) ?? {});
|
|
199
|
+
}
|
|
200
|
+
catch (_e) {
|
|
201
|
+
/* no (valid) cache yet */
|
|
202
|
+
}
|
|
203
|
+
if (typeof cache.time === "number" && Math.abs(Date.now() - cache.time) < CODEX_USAGE_TTL)
|
|
204
|
+
return cache.limits;
|
|
205
|
+
/* query the usage endpoint (keeping the stale result on any failure) */
|
|
206
|
+
let limits = cache.limits;
|
|
207
|
+
try {
|
|
208
|
+
const home = process.env.CODEX_HOME ?? path.join(os.homedir(), ".codex");
|
|
209
|
+
const auth = JSON.parse(fs.readFileSync(path.join(home, "auth.json"), "utf8"));
|
|
210
|
+
const token = auth?.tokens?.access_token;
|
|
211
|
+
if (typeof token === "string" && token !== "") {
|
|
212
|
+
const res = await fetch(CODEX_USAGE, {
|
|
213
|
+
headers: {
|
|
214
|
+
"Authorization": `Bearer ${token}`,
|
|
215
|
+
"ChatGPT-Account-ID": auth?.tokens?.account_id ?? "",
|
|
216
|
+
"User-Agent": `ase/${pkg.version}`
|
|
217
|
+
},
|
|
218
|
+
signal: AbortSignal.timeout(3 * 1000)
|
|
219
|
+
});
|
|
220
|
+
if (res.ok) {
|
|
221
|
+
/* classify windows by their length, as plans without a 5h limit
|
|
222
|
+
report the 7d window in the primary slot */
|
|
223
|
+
const usage = await res.json();
|
|
224
|
+
const wins = [usage?.rate_limit?.primary_window, usage?.rate_limit?.secondary_window]
|
|
225
|
+
.filter((w) => w !== undefined && w !== null);
|
|
226
|
+
const win5h = wins.find((w) => (w.limit_window_seconds ?? 5 * 3600) < 24 * 3600);
|
|
227
|
+
const win7d = wins.find((w) => (w.limit_window_seconds ?? 0) >= 24 * 3600);
|
|
228
|
+
limits = {};
|
|
229
|
+
if (win5h !== undefined)
|
|
230
|
+
limits.five_hour = { used_percentage: win5h.used_percent, resets_at: win5h.reset_at };
|
|
231
|
+
if (win7d !== undefined)
|
|
232
|
+
limits.seven_day = { used_percentage: win7d.used_percent, resets_at: win7d.reset_at };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (_e) {
|
|
237
|
+
/* credential unreadable or endpoint unreachable */
|
|
238
|
+
}
|
|
239
|
+
/* update the cache */
|
|
240
|
+
try {
|
|
241
|
+
fs.mkdirSync(path.dirname(cacheFile), { recursive: true });
|
|
242
|
+
fs.writeFileSync(cacheFile, JSON.stringify({ time: Date.now(), limits }) + "\n", "utf8");
|
|
243
|
+
}
|
|
244
|
+
catch (_e) {
|
|
245
|
+
/* best-effort */
|
|
246
|
+
}
|
|
247
|
+
return limits;
|
|
248
|
+
};
|
|
184
249
|
/* command-line handling */
|
|
185
250
|
export default class StatuslineCommand {
|
|
186
251
|
log;
|
|
@@ -209,7 +274,7 @@ export default class StatuslineCommand {
|
|
|
209
274
|
.option("-p, --padding <n>", "pad each rendered line with <n> spaces on each side", parseInteger("--padding"), 0)
|
|
210
275
|
.option("--no-icons", "disable icons in placeholder rendering")
|
|
211
276
|
.option("--no-labels", "disable labels in front of bold values")
|
|
212
|
-
.argument("[lines...]", "one or more template lines with %u %p %T %s %m %e %t %O %P %h %B %c %C %a %r " +
|
|
277
|
+
.argument("[lines...]", "one or more template lines with %u %p %T %s %m %e %t %O %P %h %B %L %c %C %a %r " +
|
|
213
278
|
"%S %D %W %Q %H %X %b %g %G %d %M %V placeholders and <color>...</color> markup " +
|
|
214
279
|
"(color: black, red, green, yellow, blue, magenta, cyan, white, default) " +
|
|
215
280
|
"(default: single line \"%m %e %t\")")
|
|
@@ -282,30 +347,32 @@ export default class StatuslineCommand {
|
|
|
282
347
|
post-loop tmux publish for the Config cascade) */
|
|
283
348
|
const getSession = memoize(() => data.session_id ?? "unknown");
|
|
284
349
|
const getCfg = memoize(() => {
|
|
285
|
-
let taskId = process.env.ASE_TASK_ID ?? "";
|
|
350
|
+
let taskId = process.env.ASE_TASK_ID ?? "default";
|
|
286
351
|
let persona = process.env.ASE_PERSONA_STYLE ?? "";
|
|
287
352
|
let guidance = process.env.ASE_GUIDANCE_LEVEL ?? "";
|
|
288
353
|
let boxing = process.env.ASE_PROJECT_BOXING ?? "";
|
|
354
|
+
let lifecycle = process.env.ASE_PROJECT_TASK_LIFECYCLE ?? "";
|
|
289
355
|
try {
|
|
290
356
|
const cfg = new Config("config", configSchema, this.log, parseScope(`session:${getSession()}`));
|
|
291
357
|
cfg.read("lenient");
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
taskId = t;
|
|
298
|
-
if (p !== "")
|
|
299
|
-
persona = p;
|
|
300
|
-
if (g !== "")
|
|
301
|
-
guidance = g;
|
|
302
|
-
if (b !== "")
|
|
303
|
-
boxing = b;
|
|
358
|
+
const get = (key, fallback) => String(cfg.get(key) ?? "").trim() || fallback;
|
|
359
|
+
persona = get("agent.persona", persona);
|
|
360
|
+
guidance = get("agent.guidance", guidance);
|
|
361
|
+
boxing = get("project.boxing", boxing);
|
|
362
|
+
lifecycle = get("project.task.lifecycle", lifecycle);
|
|
304
363
|
}
|
|
305
364
|
catch (_e) {
|
|
306
365
|
/* cascade unavailable; keep env-var fallbacks */
|
|
307
366
|
}
|
|
308
|
-
|
|
367
|
+
try {
|
|
368
|
+
const state = sessionState(this.log, getSession());
|
|
369
|
+
state.read("lenient");
|
|
370
|
+
taskId = String(state.get("task") ?? "").trim() || taskId;
|
|
371
|
+
}
|
|
372
|
+
catch (_e) {
|
|
373
|
+
/* session state unavailable; keep env-var fallback */
|
|
374
|
+
}
|
|
375
|
+
return { taskId, persona, guidance, boxing, lifecycle };
|
|
309
376
|
});
|
|
310
377
|
const getModel = memoize(() => {
|
|
311
378
|
const display = data.model?.display_name ?? "";
|
|
@@ -318,6 +385,19 @@ export default class StatuslineCommand {
|
|
|
318
385
|
});
|
|
319
386
|
const getGit = memoize(() => probeGit(data.workspace?.current_dir ?? ""));
|
|
320
387
|
const getMem = memoize(() => probeMemory());
|
|
388
|
+
/* determine the rate-limit windows: regularly supplied by the harness on stdin,
|
|
389
|
+
but for OpenAI GPT models fetched directly as a fallback (and only on demand) */
|
|
390
|
+
let limits = data.rate_limits;
|
|
391
|
+
if (limits?.five_hour === undefined && limits?.seven_day === undefined
|
|
392
|
+
&& /^gpt-.+/i.test(getModel().name)
|
|
393
|
+
&& tmpl.some((line) => /%[SDWQ]/.test(line)))
|
|
394
|
+
limits = await fetchCodexLimits();
|
|
395
|
+
/* render a configuration value (if non-empty) with its icon and label */
|
|
396
|
+
const cfgValue = (key, icon, label) => () => {
|
|
397
|
+
const value = getCfg()[key];
|
|
398
|
+
if (value !== "")
|
|
399
|
+
emit(`${prefix(icon, label)}${c.bold(value)}`);
|
|
400
|
+
};
|
|
321
401
|
/* identifier to renderer map: each callback fetches its own information
|
|
322
402
|
directly from data (or via the lazy helpers above for shared values) */
|
|
323
403
|
const renderers = {
|
|
@@ -327,14 +407,10 @@ export default class StatuslineCommand {
|
|
|
327
407
|
emit(`${prefix("※", "user")}${c.bold(user)}`);
|
|
328
408
|
},
|
|
329
409
|
p: () => {
|
|
330
|
-
const
|
|
331
|
-
emit(`${prefix("⚑", "project")}${c.bold(
|
|
332
|
-
},
|
|
333
|
-
T: () => {
|
|
334
|
-
const { taskId } = getCfg();
|
|
335
|
-
if (taskId !== "")
|
|
336
|
-
emit(`${prefix("◉", "task")}${c.bold(taskId)}`);
|
|
410
|
+
const id = projectIdOf(data.workspace?.current_dir ?? "");
|
|
411
|
+
emit(`${prefix("⚑", "project")}${c.bold(id)}`);
|
|
337
412
|
},
|
|
413
|
+
T: cfgValue("taskId", "◉", "task"),
|
|
338
414
|
s: () => emit(`${prefix("⏻", "session")}${c.bold(getSession())}`),
|
|
339
415
|
/* ==== MODEL ==== */
|
|
340
416
|
m: () => {
|
|
@@ -355,21 +431,10 @@ export default class StatuslineCommand {
|
|
|
355
431
|
if (styleName !== "")
|
|
356
432
|
emit(`${prefix("≡", "style")}${c.bold(styleName)}`);
|
|
357
433
|
},
|
|
358
|
-
P: (
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
},
|
|
363
|
-
h: () => {
|
|
364
|
-
const { guidance } = getCfg();
|
|
365
|
-
if (guidance !== "")
|
|
366
|
-
emit(`${prefix("▶", "guidance")}${c.bold(guidance)}`);
|
|
367
|
-
},
|
|
368
|
-
B: () => {
|
|
369
|
-
const { boxing } = getCfg();
|
|
370
|
-
if (boxing !== "")
|
|
371
|
-
emit(`${prefix("▢", "boxing")}${c.bold(boxing)}`);
|
|
372
|
-
},
|
|
434
|
+
P: cfgValue("persona", "☯", "persona"),
|
|
435
|
+
h: cfgValue("guidance", "▶", "guidance"),
|
|
436
|
+
B: cfgValue("boxing", "▢", "boxing"),
|
|
437
|
+
L: cfgValue("lifecycle", "⟳", "lifecycle"),
|
|
373
438
|
/* ==== CONTEXT ==== */
|
|
374
439
|
c: () => {
|
|
375
440
|
const pct = Math.min(100, Math.max(0, Math.floor(data.context_window?.used_percentage ?? 0)));
|
|
@@ -396,22 +461,22 @@ export default class StatuslineCommand {
|
|
|
396
461
|
},
|
|
397
462
|
/* ==== RATE LIMITS ==== */
|
|
398
463
|
S: () => {
|
|
399
|
-
const pct5h =
|
|
464
|
+
const pct5h = limits?.five_hour?.used_percentage;
|
|
400
465
|
const s = pct5h !== undefined ? `${pct5h.toFixed(1)}%` : "-";
|
|
401
466
|
emit(`${prefix("⏲", "5h-usage")}${c.bold(s)}`);
|
|
402
467
|
},
|
|
403
468
|
D: () => {
|
|
404
|
-
const until5h =
|
|
469
|
+
const until5h = limits?.five_hour?.resets_at;
|
|
405
470
|
const s = formatTimeUntil(until5h);
|
|
406
471
|
emit(`${prefix("⏱", "5h-resets")}${c.bold(s !== "" ? s : "-")}`);
|
|
407
472
|
},
|
|
408
473
|
W: () => {
|
|
409
|
-
const pctWk =
|
|
474
|
+
const pctWk = limits?.seven_day?.used_percentage;
|
|
410
475
|
const s = pctWk !== undefined ? `${pctWk.toFixed(1)}%` : "-";
|
|
411
476
|
emit(`${prefix("⏲", "7d-usage")}${c.bold(s)}`);
|
|
412
477
|
},
|
|
413
478
|
Q: () => {
|
|
414
|
-
const untilWk =
|
|
479
|
+
const untilWk = limits?.seven_day?.resets_at;
|
|
415
480
|
const s = formatTimeUntil(untilWk);
|
|
416
481
|
emit(`${prefix("⏱", "7d-resets")}${c.bold(s !== "" ? s : "-")}`);
|
|
417
482
|
},
|