gemiterm 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +32 -9
  2. package/package.json +13 -4
  3. package/src/cli/command-registry.ts +66 -62
  4. package/src/cli/commands/continue-command.ts +75 -1
  5. package/src/cli/commands/install-skills-command.ts +35 -0
  6. package/src/cli/commands/new-command.ts +62 -0
  7. package/src/cli/index.ts +19 -44
  8. package/src/cli/utils/long-arg-guard.ts +28 -0
  9. package/src/cli/utils/prompt-file.ts +26 -0
  10. package/src/infrastructure/cli-parser.ts +77 -0
  11. package/src/infrastructure/io.ts +9 -0
  12. package/src/services/skills-cli-driver.ts +58 -0
  13. package/src/services/skills-service.ts +52 -0
  14. package/.env +0 -2
  15. package/.github/workflows/manual-release.yml +0 -34
  16. package/.github/workflows/release.yml +0 -198
  17. package/.github/workflows/test.yml +0 -29
  18. package/.opencode/commands/opsx-apply.md +0 -152
  19. package/.opencode/commands/opsx-archive.md +0 -157
  20. package/.opencode/commands/opsx-explore.md +0 -169
  21. package/.opencode/commands/opsx-propose.md +0 -104
  22. package/.opencode/commands/opsx-sync.md +0 -140
  23. package/.opencode/commands/search-intelligently.md +0 -9
  24. package/.opencode/opencode.json +0 -20
  25. package/.opencode/skills/intellisearch/.version +0 -1
  26. package/.opencode/skills/intellisearch/SKILL.md +0 -84
  27. package/.opencode/skills/intellisearch/references/brave-search.md +0 -67
  28. package/.opencode/skills/intellisearch/references/ddg-search.md +0 -79
  29. package/.opencode/skills/intellisearch/references/deepwiki-tools.md +0 -246
  30. package/.opencode/skills/intellisearch/references/examples.md +0 -97
  31. package/.opencode/skills/intellisearch/references/gh-cli.md +0 -143
  32. package/.opencode/skills/intellisearch/references/google-search.md +0 -40
  33. package/.opencode/skills/intellisearch/references/search-workflow.md +0 -143
  34. package/.opencode/skills/intellisearch/references/workflow.md +0 -115
  35. package/.opencode/skills/openspec-apply-change/SKILL.md +0 -159
  36. package/.opencode/skills/openspec-archive-change/SKILL.md +0 -117
  37. package/.opencode/skills/openspec-explore/SKILL.md +0 -287
  38. package/.opencode/skills/openspec-propose/SKILL.md +0 -111
  39. package/.opencode/skills/openspec-sync-specs/SKILL.md +0 -147
  40. package/.serena/project.yml +0 -133
  41. package/AGENTS.md +0 -136
  42. package/CHANGELOG.md +0 -3
  43. package/bun.lock +0 -105
  44. package/docs/INSTALL.md +0 -185
  45. package/docs/PLAYWRIGHT_CLI_API.md +0 -306
  46. package/docs/python-release-for-reference.md +0 -175
  47. package/examples/sample_json_export.json +0 -32
  48. package/examples/sample_markdown_export.md +0 -221
  49. package/examples/usage_examples.sh +0 -222
  50. package/install.ps1 +0 -264
  51. package/install.sh +0 -275
  52. package/openspec/MAESTRO_MIGRATION.md +0 -180
  53. package/openspec/changes/archive/2026-06-08-command-spec-conformance/.openspec.yaml +0 -2
  54. package/openspec/changes/archive/2026-06-08-command-spec-conformance/design.md +0 -194
  55. package/openspec/changes/archive/2026-06-08-command-spec-conformance/proposal.md +0 -52
  56. package/openspec/changes/archive/2026-06-08-command-spec-conformance/specs/multi-profile-conversations/spec.md +0 -133
  57. package/openspec/changes/archive/2026-06-08-command-spec-conformance/tasks.md +0 -95
  58. package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/.openspec.yaml +0 -2
  59. package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/design.md +0 -28
  60. package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/proposal.md +0 -22
  61. package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/specs/interactive-prompt-loop/spec.md +0 -35
  62. package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/tasks.md +0 -28
  63. package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/.openspec.yaml +0 -2
  64. package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/design.md +0 -323
  65. package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/proposal.md +0 -122
  66. package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/specs/no-capability-changes/spec.md +0 -29
  67. package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/tasks.md +0 -172
  68. package/openspec/changes/archive/2026-06-09-v2-install-migration/.openspec.yaml +0 -2
  69. package/openspec/changes/archive/2026-06-09-v2-install-migration/design.md +0 -241
  70. package/openspec/changes/archive/2026-06-09-v2-install-migration/proposal.md +0 -41
  71. package/openspec/changes/archive/2026-06-09-v2-install-migration/specs/v2-installer/spec.md +0 -205
  72. package/openspec/changes/archive/2026-06-09-v2-install-migration/tasks.md +0 -97
  73. package/openspec/changes/commander-cli-parser/.openspec.yaml +0 -2
  74. package/openspec/changes/commander-cli-parser/design.md +0 -107
  75. package/openspec/changes/commander-cli-parser/proposal.md +0 -31
  76. package/openspec/changes/commander-cli-parser/specs/cli/spec.md +0 -48
  77. package/openspec/changes/commander-cli-parser/tasks.md +0 -33
  78. package/openspec/changes/cross-platform-build-and-ci/.openspec.yaml +0 -2
  79. package/openspec/changes/cross-platform-build-and-ci/design.md +0 -213
  80. package/openspec/changes/cross-platform-build-and-ci/proposal.md +0 -50
  81. package/openspec/changes/cross-platform-build-and-ci/specs/path-and-file-mediation/spec.md +0 -335
  82. package/openspec/changes/cross-platform-build-and-ci/specs/release-pipeline/spec.md +0 -95
  83. package/openspec/changes/cross-platform-build-and-ci/tasks.md +0 -164
  84. package/openspec/config.yaml +0 -20
  85. package/openspec/specs/auth/spec.md +0 -394
  86. package/openspec/specs/cli/spec.md +0 -108
  87. package/openspec/specs/commands/spec.md +0 -409
  88. package/openspec/specs/configuration/spec.md +0 -130
  89. package/openspec/specs/conversations/spec.md +0 -139
  90. package/openspec/specs/domain-model/spec.md +0 -128
  91. package/openspec/specs/formatters/spec.md +0 -158
  92. package/openspec/specs/install-browser/spec.md +0 -146
  93. package/openspec/specs/interactive-prompt-loop/spec.md +0 -41
  94. package/openspec/specs/logger/spec.md +0 -71
  95. package/openspec/specs/mediator/spec.md +0 -72
  96. package/openspec/specs/multi-profile-conversations/spec.md +0 -145
  97. package/openspec/specs/path-utils/spec.md +0 -101
  98. package/openspec/specs/profiles/spec.md +0 -94
  99. package/openspec/specs/storage/spec.md +0 -198
  100. package/openspec/specs/testing/spec.md +0 -237
  101. package/openspec/specs/v2-installer/spec.md +0 -205
  102. package/openspec/specs/validators/spec.md +0 -65
  103. package/scripts/build.ts +0 -88
  104. package/scripts/clean-build.ps1 +0 -4
  105. package/scripts/clean-build.sh +0 -5
  106. package/scripts/install-browser.ps1 +0 -5
  107. package/scripts/install-browser.sh +0 -6
  108. package/scripts/lint-path-mediation.ps1 +0 -65
  109. package/scripts/lint-path-mediation.sh +0 -40
  110. package/tests/cli/auth-command.test.ts +0 -220
  111. package/tests/cli/command-registry.test.ts +0 -67
  112. package/tests/cli/continue-command.test.ts +0 -100
  113. package/tests/cli/delete-command.test.ts +0 -128
  114. package/tests/cli/export-all-command.test.ts +0 -375
  115. package/tests/cli/install-browser-command.test.ts +0 -48
  116. package/tests/cli/list-command.test.ts +0 -179
  117. package/tests/cli/new-command.test.ts +0 -139
  118. package/tests/cli/status-command.test.ts +0 -106
  119. package/tests/core/query-handlers.test.ts +0 -187
  120. package/tests/fixtures/auth-fixtures.ts +0 -98
  121. package/tests/fixtures/chat-fixtures.ts +0 -87
  122. package/tests/infrastructure/cli-table.test.ts +0 -107
  123. package/tests/infrastructure/formatters.test.ts +0 -202
  124. package/tests/infrastructure/io.test.ts +0 -197
  125. package/tests/infrastructure/logger.test.ts +0 -74
  126. package/tests/infrastructure/storage.test.ts +0 -335
  127. package/tests/infrastructure/validators.test.ts +0 -67
  128. package/tests/integration/commands/auth.test.ts +0 -186
  129. package/tests/integration/commands/continue.test.ts +0 -130
  130. package/tests/integration/commands/delete.test.ts +0 -140
  131. package/tests/integration/commands/export.test.ts +0 -266
  132. package/tests/integration/commands/fetch.test.ts +0 -238
  133. package/tests/integration/commands/list.test.ts +0 -281
  134. package/tests/integration/commands/profile.test.ts +0 -258
  135. package/tests/integration/commands/status.test.ts +0 -223
  136. package/tests/integration/installer-script-shape.test.ts +0 -67
  137. package/tests/parity/compare-outputs.ts +0 -359
  138. package/tests/parity/test-commands-parity.ps1 +0 -82
  139. package/tests/parity/test-commands-parity.sh +0 -61
  140. package/tests/services/auth-service.test.ts +0 -315
  141. package/tests/services/cookie-monitor.test.ts +0 -229
  142. package/tests/services/cookie-storage-service.test.ts +0 -230
  143. package/tests/services/gemini-client-wrapper.test.ts +0 -688
  144. package/tests/services/install-browser-service.test.ts +0 -83
  145. package/tests/services/playwright-cli-driver.test.ts +0 -468
  146. package/tests/services/profile-auth-manager.test.ts +0 -334
  147. package/tests/services/profile-service.test.ts +0 -224
  148. package/tests/setup.ts +0 -95
  149. package/tests/smoke/smoke.test.ts +0 -52
  150. package/tests/unit/config.test.ts +0 -159
  151. package/tests/unit/errors.test.ts +0 -119
  152. package/tests/unit/formatters.test.ts +0 -316
  153. package/tests/unit/mediator.test.ts +0 -152
  154. package/tests/unit/path-utils.test.ts +0 -289
  155. package/tsconfig.json +0 -16
@@ -0,0 +1,77 @@
1
+ import { Command, CommanderError } from "commander";
2
+ import type { CommandRegistry } from "../cli/command-registry.ts";
3
+ import { showHelp } from "../cli/commands/help.ts";
4
+
5
+ export interface ParsedFlags {
6
+ verbose: boolean;
7
+ version: boolean;
8
+ help: boolean;
9
+ }
10
+
11
+ export interface ParsedArgs {
12
+ flags: ParsedFlags;
13
+ subcommand: string | null;
14
+ subcommandArgs: string[];
15
+ }
16
+
17
+ function splitAtFirstNonFlag(argv: string[]): { pre: string[]; post: string[] } {
18
+ const pre: string[] = [];
19
+ const post: string[] = [];
20
+ let found = false;
21
+ for (const arg of argv) {
22
+ if (!found && !arg.startsWith("-")) {
23
+ found = true;
24
+ post.push(arg);
25
+ continue;
26
+ }
27
+ if (found) {
28
+ post.push(arg);
29
+ } else {
30
+ pre.push(arg);
31
+ }
32
+ }
33
+ return { pre, post };
34
+ }
35
+
36
+ export function parseGlobalArgs(argv: string[]): ParsedArgs {
37
+ const { pre, post } = splitAtFirstNonFlag(argv);
38
+ const subcommand = post[0] ?? null;
39
+ const subcommandArgs = post.slice(1);
40
+
41
+ const program = new Command();
42
+ program
43
+ .exitOverride()
44
+ .allowUnknownOption(false)
45
+ .allowExcessArguments(true)
46
+ .helpOption(false)
47
+ .configureOutput({ writeErr: () => {} })
48
+ .option("-v, --verbose", "enable verbose output")
49
+ .option("--version", "show version number")
50
+ .option("-h, --help", "show help");
51
+
52
+ try {
53
+ program.parse(pre, { from: "user" });
54
+ } catch (error) {
55
+ if (error instanceof CommanderError) {
56
+ throw new Error("gemiterm: " + error.message);
57
+ }
58
+ throw error;
59
+ }
60
+
61
+ const opts = program.opts<{ verbose?: boolean; version?: boolean; help?: boolean }>();
62
+ const flags: ParsedFlags = {
63
+ verbose: Boolean(opts.verbose),
64
+ version: Boolean(opts.version),
65
+ help: Boolean(opts.help),
66
+ };
67
+
68
+ return { flags, subcommand, subcommandArgs };
69
+ }
70
+
71
+ export function printVersion(pkgVersion: string): void {
72
+ console.log(`gemiterm v${pkgVersion}`);
73
+ }
74
+
75
+ export function printHelp(registry: CommandRegistry): void {
76
+ showHelp(registry);
77
+ }
@@ -114,6 +114,14 @@ function removeDir(path: string): void {
114
114
  }
115
115
  }
116
116
 
117
+ function removeFile(path: string): void {
118
+ try {
119
+ rmSync(path, { force: true });
120
+ } catch (err) {
121
+ throw wrap("removeFile", path, err instanceof Error ? err : undefined);
122
+ }
123
+ }
124
+
117
125
  function renameDir(src: string, dest: string): void {
118
126
  try {
119
127
  renameSync(src, dest);
@@ -155,6 +163,7 @@ export {
155
163
  readJsonFile,
156
164
  writeJsonFile,
157
165
  removeDir,
166
+ removeFile,
158
167
  renameDir,
159
168
  isDirectory,
160
169
  listSubdirectories,
@@ -0,0 +1,58 @@
1
+ import { Logger } from "../infrastructure/logger.ts";
2
+
3
+ export class SkillsCliError extends Error {
4
+ constructor(command: string, exitCode: number, stderr: string) {
5
+ super(`skills '${command}' exited with code ${exitCode}: ${stderr}`);
6
+ this.name = "SkillsCliError";
7
+ }
8
+ }
9
+
10
+ export interface SkillsRunnerResult {
11
+ exitCode: number;
12
+ stdout: string;
13
+ stderr: string;
14
+ }
15
+
16
+ export interface SkillsRunner {
17
+ run(args: string[]): Promise<SkillsRunnerResult>;
18
+ }
19
+
20
+ export class BunSkillsRunner implements SkillsRunner {
21
+ async run(args: string[]): Promise<SkillsRunnerResult> {
22
+ const proc = Bun.spawn(["npx", "skills", ...args], {
23
+ stdout: "pipe",
24
+ stderr: "pipe",
25
+ stdin: "ignore",
26
+ });
27
+ const [stdout, stderr, exitCode] = await Promise.all([
28
+ new Response(proc.stdout).text(),
29
+ new Response(proc.stderr).text(),
30
+ proc.exited,
31
+ ]);
32
+ return { exitCode: exitCode ?? -1, stdout: stdout.trim(), stderr: stderr.trim() };
33
+ }
34
+ }
35
+
36
+ export interface SkillsCliDriverOptions {
37
+ logger?: Logger;
38
+ runner?: SkillsRunner;
39
+ }
40
+
41
+ export class SkillsCliDriver {
42
+ private readonly logger: Logger;
43
+ private readonly runner: SkillsRunner;
44
+
45
+ constructor(opts: SkillsCliDriverOptions = {}) {
46
+ this.logger = opts.logger ?? new Logger("skills-cli-driver");
47
+ this.runner = opts.runner ?? new BunSkillsRunner();
48
+ }
49
+
50
+ async run(args: string[]): Promise<string> {
51
+ this.logger.debug(`Running: npx skills ${args.join(" ")}`);
52
+ const result = await this.runner.run(args);
53
+ if (result.exitCode !== 0) {
54
+ throw new SkillsCliError(args.join(" "), result.exitCode, result.stderr);
55
+ }
56
+ return result.stdout;
57
+ }
58
+ }
@@ -0,0 +1,52 @@
1
+ import { Logger } from "../infrastructure/logger.ts";
2
+ import { SkillsCliDriver, SkillsCliDriverOptions, SkillsCliError } from "./skills-cli-driver.ts";
3
+
4
+ export class SkillsInstallError extends Error {
5
+ constructor(message: string, public readonly cause?: Error) {
6
+ super(message);
7
+ this.name = "SkillsInstallError";
8
+ }
9
+ }
10
+
11
+ export interface InstallSkillsServiceOptions {
12
+ logger?: Logger;
13
+ driver?: SkillsCliDriver;
14
+ repo?: string;
15
+ skills?: string[];
16
+ }
17
+
18
+ export class InstallSkillsService {
19
+ private readonly logger: Logger;
20
+ private readonly driver: SkillsCliDriver;
21
+ private readonly repo: string;
22
+ private readonly skills: string[];
23
+
24
+ constructor(opts: InstallSkillsServiceOptions = {}) {
25
+ this.logger = opts.logger ?? new Logger("install-skills-service");
26
+ this.repo = opts.repo ?? "expert-vision-software/opencode-gemiterm-skills";
27
+ this.skills = opts.skills ?? ["gemiterm", "debate-with-gemini"];
28
+ this.driver = opts.driver ?? new SkillsCliDriver({ logger: this.logger });
29
+ }
30
+
31
+ async install(): Promise<string> {
32
+ this.logger.info(`Installing skills from ${this.repo}: ${this.skills.join(", ")}`);
33
+ const args = ["add", this.repo];
34
+ for (const skill of this.skills) {
35
+ args.push("--skill", skill);
36
+ }
37
+
38
+ try {
39
+ const output = await this.driver.run(args);
40
+ this.logger.info(`Skills installed successfully: ${output}`);
41
+ return output;
42
+ } catch (error) {
43
+ if (error instanceof SkillsCliError) {
44
+ throw new SkillsInstallError(error.message, error);
45
+ }
46
+ throw new SkillsInstallError(
47
+ `Failed to install skills: ${error instanceof Error ? error.message : String(error)}`,
48
+ error instanceof Error ? error : undefined,
49
+ );
50
+ }
51
+ }
52
+ }
package/.env DELETED
@@ -1,2 +0,0 @@
1
- GEMITERM_CONFIG_DIR=./.gemiterm
2
- GEMITERM_VERBOSE=true
@@ -1,34 +0,0 @@
1
- name: Manual Release
2
-
3
- on:
4
- workflow_dispatch:
5
- inputs:
6
- ref:
7
- description: 'Commit hash, branch, or tag to build'
8
- required: true
9
- type: string
10
- draft:
11
- description: 'Create a draft release (recommended for testing)'
12
- required: true
13
- type: boolean
14
- default: true
15
- pre_release:
16
- description: 'Mark as pre-release'
17
- required: true
18
- type: boolean
19
- default: true
20
- publish:
21
- description: 'Publish to npm (DANGEROUS — only enable if you mean it)'
22
- required: true
23
- type: boolean
24
- default: false
25
-
26
- jobs:
27
- build:
28
- uses: ./.github/workflows/release.yml
29
- with:
30
- ref: ${{ inputs.ref }}
31
- tag_name: manual-${{ inputs.ref }}-${{ github.run_id }}
32
- publish: ${{ inputs.publish }}
33
- draft: ${{ inputs.draft }}
34
- prerelease: ${{ inputs.pre_release }}
@@ -1,198 +0,0 @@
1
- name: Release
2
-
3
- on:
4
- push:
5
- tags: ['v*']
6
- workflow_call:
7
- inputs:
8
- ref:
9
- description: 'Git ref (commit hash, branch, or tag) to build'
10
- type: string
11
- default: ${{ github.ref }}
12
- tag_name:
13
- description: 'Tag name to attach the GitHub Release to'
14
- type: string
15
- default: ${{ github.ref_name }}
16
- publish:
17
- description: 'Whether to publish to npm'
18
- type: string
19
- default: 'true'
20
- draft:
21
- description: 'Whether to create the release as a draft'
22
- type: string
23
- default: 'false'
24
- prerelease:
25
- description: 'Whether to mark the release as a pre-release'
26
- type: string
27
- default: 'true'
28
-
29
- concurrency:
30
- group: release
31
- cancel-in-progress: true
32
-
33
- permissions:
34
- contents: write
35
-
36
- jobs:
37
- build-linux:
38
- name: Build Linux
39
- runs-on: ubuntu-latest
40
- steps:
41
- - uses: actions/checkout@v4
42
- with:
43
- ref: ${{ inputs.ref || github.ref }}
44
- - uses: oven-sh/setup-bun@v2
45
- with:
46
- bun-version: 1.3.13
47
- - run: bun install --frozen-lockfile
48
- - run: bun run build:linux
49
- - name: Verify binary
50
- run: test -f dist/gemiterm
51
- - name: Fail if binary < 20MB
52
- run: |
53
- size=$(stat -c%s dist/gemiterm)
54
- minsize=$((20 * 1024 * 1024))
55
- if [ "$size" -lt "$minsize" ]; then
56
- echo "Binary too small: $size bytes (expected at least 20MB)"
57
- exit 1
58
- fi
59
- - uses: actions/upload-artifact@v4
60
- with:
61
- name: GemiTerm-linux
62
- path: dist/gemiterm
63
-
64
- build-windows:
65
- name: Build Windows
66
- runs-on: windows-latest
67
- steps:
68
- - uses: actions/checkout@v4
69
- with:
70
- ref: ${{ inputs.ref || github.ref }}
71
- - uses: oven-sh/setup-bun@v2
72
- with:
73
- bun-version: 1.3.13
74
- - run: bun install --frozen-lockfile
75
- - run: bun run build:windows
76
- - name: Verify binary
77
- run: Test-Path dist/gemiterm.exe
78
- - name: Fail if binary < 20MB
79
- shell: pwsh
80
- run: |
81
- $size = (Get-Item dist/gemiterm.exe).Length
82
- $minsize = 20 * 1024 * 1024
83
- if ($size -lt $minsize) {
84
- Write-Host "Binary too small: $size bytes (expected at least 20MB)"
85
- exit 1
86
- }
87
- - uses: actions/upload-artifact@v4
88
- with:
89
- name: GemiTerm-windows
90
- path: dist/gemiterm.exe
91
-
92
- release:
93
- name: Create GitHub Release
94
- runs-on: ubuntu-latest
95
- needs: [build-linux, build-windows]
96
- steps:
97
- - uses: actions/checkout@v4
98
- with:
99
- ref: ${{ inputs.ref || github.ref }}
100
- - uses: actions/download-artifact@v4
101
- with:
102
- name: GemiTerm-linux
103
- path: dist
104
- - uses: actions/download-artifact@v4
105
- with:
106
- name: GemiTerm-windows
107
- path: dist
108
- - name: Make Linux binary executable
109
- run: chmod +x dist/gemiterm
110
- - name: Extract CHANGELOG entry for release
111
- id: changelog
112
- run: |
113
- node -e "
114
- const version = '${TAG}'.replace(/^v/, '');
115
- const fs = require('fs');
116
- const content = fs.readFileSync('CHANGELOG.md', 'utf8');
117
- const sections = content.split(/(?=^## )/m);
118
- let found = false;
119
- let notes = '';
120
- for (const section of sections) {
121
- const m = section.match(/^## \[([^\]]+)\].*?-\s*(\d{4}-\d{2}-\d{2})/s);
122
- if (m && m[1].replace(/^v/, '') === version) {
123
- notes = section.replace(/^## \[[^\]]+\].*?-\s*\d{4}-\d{2}-\d{2}\n/, '').trim();
124
- found = true;
125
- break;
126
- }
127
- }
128
- if (!found) {
129
- console.error('No changelog section found for version:', version);
130
- process.exit(1);
131
- }
132
- fs.writeFileSync('release_body.md', notes);
133
- console.log('Extracted', notes.split('\n').length, 'lines for version', version);
134
- "
135
- env:
136
- TAG: ${{ inputs.tag_name || github.ref_name }}
137
- - name: Create GitHub Release
138
- uses: softprops/action-gh-release@v2
139
- with:
140
- tag_name: ${{ inputs.tag_name || github.ref_name }}
141
- body_path: release_body.md
142
- draft: false
143
- prerelease: ${{ contains(inputs.tag_name || github.ref_name, '-') }}
144
- env:
145
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
146
- - name: Upload Linux binary
147
- run: |
148
- TAG="${{ inputs.tag_name || github.ref_name }}"
149
- gh release upload "$TAG" dist/gemiterm --clobber || true
150
- env:
151
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
152
- - name: Upload Windows binary
153
- run: |
154
- TAG="${{ inputs.tag_name || github.ref_name }}"
155
- gh release upload "$TAG" dist/gemiterm.exe --clobber || true
156
- env:
157
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
158
- - name: Set asset labels
159
- run: |
160
- TAG="${{ inputs.tag_name || github.ref_name }}"
161
- LINUX_ASSET_ID=$(gh release view "$TAG" --json assets -q '.assets[] | select(.name == "gemiterm") | .id')
162
- if [[ -n "$LINUX_ASSET_ID" ]]; then
163
- gh api -X PATCH /repos/${{ github.repository }}/releases/assets/$LINUX_ASSET_ID \
164
- -f name='GemiTerm' \
165
- -f label="GemiTerm $TAG - Linux x64 binary" || true
166
- fi
167
- WINDOWS_ASSET_ID=$(gh release view "$TAG" --json assets -q '.assets[] | select(.name == "gemiterm.exe") | .id')
168
- if [[ -n "$WINDOWS_ASSET_ID" ]]; then
169
- gh api -X PATCH /repos/${{ github.repository }}/releases/assets/$WINDOWS_ASSET_ID \
170
- -f name='GemiTerm' \
171
- -f label="GemiTerm $TAG - Windows x64 binary" || true
172
- fi
173
- env:
174
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
175
-
176
-
177
- publish:
178
- name: Publish to npm
179
- runs-on: ubuntu-latest
180
- needs: [release]
181
- if: ${{ inputs.publish != 'false' }}
182
- permissions:
183
- contents: read
184
- id-token: write
185
- steps:
186
- - uses: actions/checkout@v4
187
- with:
188
- ref: ${{ inputs.ref || github.ref }}
189
- - uses: oven-sh/setup-bun@v2
190
- with:
191
- bun-version: 1.3.13
192
- - run: bun install
193
- - name: Publish to npm
194
- run: |
195
- echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
196
- npm publish --provenance --access public
197
- env:
198
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,29 +0,0 @@
1
- name: Test
2
-
3
- on:
4
- pull_request: {}
5
- push:
6
- branches: [main]
7
-
8
- concurrency:
9
- group: ${{ github.workflow }}-${{ github.ref }}
10
- cancel-in-progress: true
11
-
12
- jobs:
13
- test:
14
- runs-on: ubuntu-latest
15
- steps:
16
- - uses: actions/checkout@v4
17
- - uses: oven-sh/setup-bun@v2
18
- with:
19
- bun-version: 1.3.13
20
- - run: bun install --frozen-lockfile
21
- - run: bun test
22
- - run: bun run typecheck
23
- - name: Enforce path-utils mediation
24
- run: |
25
- ! grep -rn --include='*.ts' "from \"node:\\(fs\\|path\\|os\\)\"" src/ \
26
- | grep -v "src/infrastructure/path-utils.ts" \
27
- | grep -v "src/infrastructure/io.ts" \
28
- | grep -v "src/services/install-browser-service.ts" \
29
- | grep -q .
@@ -1,152 +0,0 @@
1
- ---
2
- description: Implement tasks from an OpenSpec change (Experimental)
3
- ---
4
-
5
- Implement tasks from an OpenSpec change.
6
-
7
- **Input**: Optionally specify a change name (e.g., `/opsx-apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
8
-
9
- **Steps**
10
-
11
- 1. **Select the change**
12
-
13
- If a name is provided, use it. Otherwise:
14
- - Infer from conversation context if the user mentioned a change
15
- - Auto-select if only one active change exists
16
- - If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select
17
-
18
- Always announce: "Using change: <name>" and how to override (e.g., `/opsx-apply <other>`).
19
-
20
- 2. **Check status to understand the schema**
21
- ```bash
22
- openspec status --change "<name>" --json
23
- ```
24
- Parse the JSON to understand:
25
- - `schemaName`: The workflow being used (e.g., "spec-driven")
26
- - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints
27
- - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
28
-
29
- 3. **Get apply instructions**
30
-
31
- ```bash
32
- openspec instructions apply --change "<name>" --json
33
- ```
34
-
35
- This returns:
36
- - `contextFiles`: artifact ID -> array of concrete file paths (varies by schema)
37
- - Progress (total, complete, remaining)
38
- - Task list with status
39
- - Dynamic instruction based on current state
40
-
41
- **Handle states:**
42
- - If `state: "blocked"` (missing artifacts): show message, suggest using `/opsx-continue`
43
- - If `state: "all_done"`: congratulate, suggest archive
44
- - Otherwise: proceed to implementation
45
-
46
- **Workspace guard:** If status JSON reports `actionContext.mode: "workspace-planning"` and `allowedEditRoots` is empty, explain that full workspace apply is not supported in this slice. Treat linked repos and folders as read-only context, ask the user to select an affected area through an explicit implementation workflow, and STOP before editing files.
47
-
48
- 4. **Read context files**
49
-
50
- Read every file path listed under `contextFiles` from the apply instructions output.
51
- The files depend on the schema being used:
52
- - **spec-driven**: proposal, specs, design, tasks
53
- - Other schemas: follow the contextFiles from CLI output
54
-
55
- 5. **Show current progress**
56
-
57
- Display:
58
- - Schema being used
59
- - Progress: "N/M tasks complete"
60
- - Remaining tasks overview
61
- - Dynamic instruction from CLI
62
-
63
- 6. **Implement tasks (loop until done or blocked)**
64
-
65
- For each pending task:
66
- - Show which task is being worked on
67
- - Make the code changes required
68
- - Keep changes minimal and focused
69
- - Mark task complete in the tasks file: `- [ ]` → `- [x]`
70
- - Continue to next task
71
-
72
- **Pause if:**
73
- - Task is unclear → ask for clarification
74
- - Implementation reveals a design issue → suggest updating artifacts
75
- - Error or blocker encountered → report and wait for guidance
76
- - User interrupts
77
-
78
- 7. **On completion or pause, show status**
79
-
80
- Display:
81
- - Tasks completed this session
82
- - Overall progress: "N/M tasks complete"
83
- - If all done: suggest archive
84
- - If paused: explain why and wait for guidance
85
-
86
- **Output During Implementation**
87
-
88
- ```
89
- ## Implementing: <change-name> (schema: <schema-name>)
90
-
91
- Working on task 3/7: <task description>
92
- [...implementation happening...]
93
- ✓ Task complete
94
-
95
- Working on task 4/7: <task description>
96
- [...implementation happening...]
97
- ✓ Task complete
98
- ```
99
-
100
- **Output On Completion**
101
-
102
- ```
103
- ## Implementation Complete
104
-
105
- **Change:** <change-name>
106
- **Schema:** <schema-name>
107
- **Progress:** 7/7 tasks complete ✓
108
-
109
- ### Completed This Session
110
- - [x] Task 1
111
- - [x] Task 2
112
- ...
113
-
114
- All tasks complete! You can archive this change with `/opsx-archive`.
115
- ```
116
-
117
- **Output On Pause (Issue Encountered)**
118
-
119
- ```
120
- ## Implementation Paused
121
-
122
- **Change:** <change-name>
123
- **Schema:** <schema-name>
124
- **Progress:** 4/7 tasks complete
125
-
126
- ### Issue Encountered
127
- <description of the issue>
128
-
129
- **Options:**
130
- 1. <option 1>
131
- 2. <option 2>
132
- 3. Other approach
133
-
134
- What would you like to do?
135
- ```
136
-
137
- **Guardrails**
138
- - Keep going through tasks until done or blocked
139
- - Always read context files before starting (from the apply instructions output)
140
- - If task is ambiguous, pause and ask before implementing
141
- - If implementation reveals issues, pause and suggest artifact updates
142
- - Keep code changes minimal and scoped to each task
143
- - Update task checkbox immediately after completing each task
144
- - Pause on errors, blockers, or unclear requirements - don't guess
145
- - Use contextFiles from CLI output, don't assume specific file names
146
-
147
- **Fluid Workflow Integration**
148
-
149
- This skill supports the "actions on a change" model:
150
-
151
- - **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
152
- - **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly