deployangel 0.1.31 → 0.1.33

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9645adb2fe301ec8c10cfb61f303d8cdb5465b350889307ff82692814f531d9a
4
- data.tar.gz: 109ef3ffc37b149229be33b46463564860ceef9168b5eb26b057d82f20d66d71
3
+ metadata.gz: eb68d7ed3170cb16932b6ab0de9304c4388e9df001067cf6c0b6678e92fae0d1
4
+ data.tar.gz: dc867b57741dc75e868284fd8a1f30450d756306fcb891f66331538dacf3486f
5
5
  SHA512:
6
- metadata.gz: cf9b49285346e69ee69e1fd1ce5cf07bef673cfa0b4cafa9ee06bedf42cf8ba72bb55dfa5d6534247726c5528c447f339436064c7ab23a5bd001506e683f325f
7
- data.tar.gz: b843e7f6e991b6a7f18a42781be35bef1f353b1580a0d34dce234d39d1ed012393fab3ef227ef8e3bbede6a8b32fb9504883c72783196098ffc2344726642242
6
+ metadata.gz: 8427f099ce309a80180e0dbb3033e465e4d82c8ad6f0f72c803623594feb6b9a831a16e7ec25c21e866c792d0acfa50d39f453eb17b2d282f32bd765f8133be4
7
+ data.tar.gz: 4c19dc7ec0a6730724a466dc51b91f99bddf073b9dc3af480a584ee62417a7637543f64f8f9d4784be176416067162ad79200031e22ed180eb30c70da7ec7072
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.33 (2026-10-28)
4
+
5
+ - An exception whose message has bytes that aren't valid UTF-8, as a
6
+ message can when it quotes a malformed request, is now recorded. The bad
7
+ bytes become U+FFFD. Before, the agent dropped the exception with a
8
+ warning (`Encoding::CompatibilityError`), though the request's 500 still
9
+ counted.
10
+
11
+ ## 0.1.32 (2026-10-21)
12
+
13
+ - `deployangel mcp` starts without an API token. Each tool then answers with
14
+ how to set `DEPLOYANGEL_API_TOKEN` (or run `deployangel setup`), instead of
15
+ the server failing to start, which many coding agents only report as
16
+ "failed to start".
17
+
3
18
  ## 0.1.31 (2026-10-21)
4
19
 
5
20
  - The instructions `deployangel install agents` writes to `AGENTS.md` now tell
@@ -555,10 +555,18 @@ module DeployAngel
555
555
  lines.join
556
556
  end
557
557
 
558
+ # Without a token the server still starts, and each tool says how to set
559
+ # one: many agents only report a server that won't start as "failed to
560
+ # start", with no reason.
558
561
  def mcp
559
562
  require_relative "mcp"
563
+ token_missing = @client.nil? && api_token.to_s.empty?
564
+ if token_missing
565
+ @stderr.puts("deployangel mcp: no API token yet; each tool will say how to set one.")
566
+ @client = Client.new(token: nil, endpoint: endpoint, require_token: false)
567
+ end
560
568
  MCP::Server.new(client: client, input: @stdin, output: @stdout, error_output: @stderr,
561
- sleeper: @sleeper, clock: @clock, git_head: method(:git_head)).run
569
+ sleeper: @sleeper, clock: @clock, git_head: method(:git_head), token_missing: token_missing).run
562
570
  0
563
571
  end
564
572
 
@@ -608,8 +616,11 @@ module DeployAngel
608
616
 
609
617
  # DEPLOYANGEL_API_TOKEN, else the token `deployangel setup` saved here.
610
618
  def client
611
- token = @env["DEPLOYANGEL_API_TOKEN"].to_s.empty? ? saved_credentials["api_token"] : @env["DEPLOYANGEL_API_TOKEN"]
612
- @client ||= Client.new(token: token, endpoint: endpoint)
619
+ @client ||= Client.new(token: api_token, endpoint: endpoint)
620
+ end
621
+
622
+ def api_token
623
+ @env["DEPLOYANGEL_API_TOKEN"].to_s.empty? ? saved_credentials["api_token"] : @env["DEPLOYANGEL_API_TOKEN"]
613
624
  end
614
625
 
615
626
  def endpoint
@@ -55,7 +55,7 @@ module DeployAngel
55
55
  # Only quoted values, numbers, emails, UUIDs, and long hex are replaced;
56
56
  # unquoted words, such as a name in a message the app builds, are kept.
57
57
  def normalize_message(message, redactions = [])
58
- text = message.to_s.lines.first.to_s.strip
58
+ text = utf8(message.to_s).lines.first.to_s.strip
59
59
  redactions.each do |value, placeholder|
60
60
  text = text.gsub(/(?<![[:alnum:]])#{Regexp.escape(value)}(?![[:alnum:]])/i, placeholder)
61
61
  end
@@ -63,6 +63,15 @@ module DeployAngel
63
63
  text[0, MAX_MESSAGE]
64
64
  end
65
65
 
66
+ # A message can carry bytes from a request (a header, a path, a body)
67
+ # that aren't valid UTF-8, which matching and the JSON payload both
68
+ # reject, and the exception would go unrecorded. Bad bytes become U+FFFD.
69
+ def utf8(text)
70
+ text = text.dup.force_encoding(Encoding::UTF_8) if text.encoding == Encoding::BINARY
71
+ text = text.encode(Encoding::UTF_8, invalid: :replace, undef: :replace) unless text.encoding == Encoding::UTF_8
72
+ text.scrub
73
+ end
74
+
66
75
  def app_frame?(frame)
67
76
  frame.start_with?("app/", "lib/", "config/")
68
77
  end
@@ -39,11 +39,14 @@ module DeployAngel
39
39
  "latest" => { "type" => "boolean", "description" => "Use the most recent deployment." }
40
40
  }.freeze
41
41
 
42
+ MISSING_TOKEN = "DeployAngel has no API token yet. Set DEPLOYANGEL_API_TOKEN to a \"CLI & coding agents\" token " \
43
+ "from your app's Settings in DeployAngel, or run `deployangel setup` in the project, then restart this MCP server."
42
44
  ERROR_CODES = { parse: -32_700, invalid: -32_600, method: -32_601, params: -32_602, internal: -32_603 }.freeze
43
45
 
44
46
  def initialize(client:, input: $stdin, output: $stdout, error_output: $stderr,
45
- sleeper: ->(seconds) { sleep(seconds) }, clock: -> { Time.now }, git_head: -> {})
47
+ sleeper: ->(seconds) { sleep(seconds) }, clock: -> { Time.now }, git_head: -> {}, token_missing: false)
46
48
  @client = client
49
+ @token_missing = token_missing
47
50
  @input = input
48
51
  @output = output
49
52
  @error_output = error_output
@@ -138,6 +141,8 @@ module DeployAngel
138
141
  end
139
142
 
140
143
  def call_tool(name, arguments)
144
+ return { "content" => [ { "type" => "text", "text" => MISSING_TOKEN } ], "isError" => true } if @token_missing
145
+
141
146
  content =
142
147
  case name
143
148
  when "get_verification" then waiter.wait(target(arguments), wait: false).then { |o| verification_content(o) }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeployAngel
4
- VERSION = "0.1.31"
4
+ VERSION = "0.1.33"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deployangel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.31
4
+ version: 0.1.33
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Owens