@harborppm/cli 0.95.0 → 0.96.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.
Files changed (2) hide show
  1. package/dist/app.mjs +560 -0
  2. package/package.json +1 -1
package/dist/app.mjs CHANGED
@@ -6818,6 +6818,534 @@ function applyTheme(name) {
6818
6818
  }
6819
6819
  applyTheme("dark");
6820
6820
 
6821
+ // src/lib/signal-flags.ts
6822
+ const FLAG_W = 30;
6823
+ const FLAG_H = 20;
6824
+ const W = 30;
6825
+ const H = 20;
6826
+ const full = (c) => ({
6827
+ r: [
6828
+ 0,
6829
+ 0,
6830
+ W,
6831
+ H
6832
+ ],
6833
+ c
6834
+ });
6835
+ const rows = (...cs) => cs.map((c, i) => ({
6836
+ r: [
6837
+ 0,
6838
+ H / cs.length * i,
6839
+ W,
6840
+ H / cs.length
6841
+ ],
6842
+ c
6843
+ }));
6844
+ const cols = (...cs) => cs.map((c, i) => ({
6845
+ r: [
6846
+ W / cs.length * i,
6847
+ 0,
6848
+ W / cs.length,
6849
+ H
6850
+ ],
6851
+ c
6852
+ }));
6853
+ const quarters = (a, b, c, d) => [
6854
+ {
6855
+ r: [
6856
+ 0,
6857
+ 0,
6858
+ W / 2,
6859
+ H / 2
6860
+ ],
6861
+ c: a
6862
+ },
6863
+ {
6864
+ r: [
6865
+ W / 2,
6866
+ 0,
6867
+ W / 2,
6868
+ H / 2
6869
+ ],
6870
+ c: b
6871
+ },
6872
+ {
6873
+ r: [
6874
+ 0,
6875
+ H / 2,
6876
+ W / 2,
6877
+ H / 2
6878
+ ],
6879
+ c
6880
+ },
6881
+ {
6882
+ r: [
6883
+ W / 2,
6884
+ H / 2,
6885
+ W / 2,
6886
+ H / 2
6887
+ ],
6888
+ c: d
6889
+ }
6890
+ ];
6891
+ const square = (field, mid, inset = 6) => [full(field), {
6892
+ r: [
6893
+ inset * 1.5,
6894
+ inset,
6895
+ W - inset * 3,
6896
+ H - inset * 2
6897
+ ],
6898
+ c: mid
6899
+ }];
6900
+ const cross = (field, bar, t = 4) => [
6901
+ full(field),
6902
+ {
6903
+ r: [
6904
+ (W - t) / 2,
6905
+ 0,
6906
+ t,
6907
+ H
6908
+ ],
6909
+ c: bar
6910
+ },
6911
+ {
6912
+ r: [
6913
+ 0,
6914
+ (H - t) / 2,
6915
+ W,
6916
+ t
6917
+ ],
6918
+ c: bar
6919
+ }
6920
+ ];
6921
+ const saltire = (field, bar) => [
6922
+ full(field),
6923
+ {
6924
+ p: [
6925
+ 0,
6926
+ 0,
6927
+ 3.5,
6928
+ 0,
6929
+ W,
6930
+ 17.5,
6931
+ W,
6932
+ H,
6933
+ 26.5,
6934
+ H,
6935
+ 0,
6936
+ 2.5
6937
+ ],
6938
+ c: bar
6939
+ },
6940
+ {
6941
+ p: [
6942
+ W,
6943
+ 0,
6944
+ W,
6945
+ 2.5,
6946
+ 3.5,
6947
+ H,
6948
+ 0,
6949
+ H,
6950
+ 0,
6951
+ 17.5,
6952
+ 26.5,
6953
+ 0
6954
+ ],
6955
+ c: bar
6956
+ }
6957
+ ];
6958
+ const disc = (field, dot, r = 5.5) => [full(field), {
6959
+ o: [
6960
+ W / 2,
6961
+ H / 2,
6962
+ r
6963
+ ],
6964
+ c: dot
6965
+ }];
6966
+ /** The 26 letter flags. */
6967
+ const LETTERS = {
6968
+ A: [
6969
+ "Alfa",
6970
+ cols("w", "b"),
6971
+ ["w", "b"]
6972
+ ],
6973
+ B: [
6974
+ "Bravo",
6975
+ [full("r")],
6976
+ ["r", "r"]
6977
+ ],
6978
+ C: [
6979
+ "Charlie",
6980
+ rows("b", "w", "r", "w", "b"),
6981
+ ["b", "r"]
6982
+ ],
6983
+ D: [
6984
+ "Delta",
6985
+ [full("y"), {
6986
+ r: [
6987
+ 0,
6988
+ H / 4,
6989
+ W,
6990
+ H / 2
6991
+ ],
6992
+ c: "b"
6993
+ }],
6994
+ ["y", "b"]
6995
+ ],
6996
+ E: [
6997
+ "Echo",
6998
+ rows("b", "r"),
6999
+ ["b", "r"]
7000
+ ],
7001
+ F: [
7002
+ "Foxtrot",
7003
+ [full("w"), {
7004
+ p: [
7005
+ W / 2,
7006
+ 1,
7007
+ 29,
7008
+ H / 2,
7009
+ W / 2,
7010
+ 19,
7011
+ 1,
7012
+ H / 2
7013
+ ],
7014
+ c: "r"
7015
+ }],
7016
+ ["w", "r"]
7017
+ ],
7018
+ G: [
7019
+ "Golf",
7020
+ cols("y", "b", "y", "b", "y", "b"),
7021
+ ["y", "b"]
7022
+ ],
7023
+ H: [
7024
+ "Hotel",
7025
+ cols("w", "r"),
7026
+ ["w", "r"]
7027
+ ],
7028
+ I: [
7029
+ "India",
7030
+ disc("y", "k"),
7031
+ ["y", "k"]
7032
+ ],
7033
+ J: [
7034
+ "Juliett",
7035
+ rows("b", "w", "b"),
7036
+ ["b", "w"]
7037
+ ],
7038
+ K: [
7039
+ "Kilo",
7040
+ cols("y", "b"),
7041
+ ["y", "b"]
7042
+ ],
7043
+ L: [
7044
+ "Lima",
7045
+ quarters("y", "k", "k", "y"),
7046
+ ["y", "k"]
7047
+ ],
7048
+ M: [
7049
+ "Mike",
7050
+ saltire("b", "w"),
7051
+ ["b", "w"]
7052
+ ],
7053
+ N: [
7054
+ "November",
7055
+ [full("w"), ...[
7056
+ 0,
7057
+ 1,
7058
+ 2,
7059
+ 3
7060
+ ].flatMap((row) => [
7061
+ 0,
7062
+ 1,
7063
+ 2,
7064
+ 3
7065
+ ].filter((col) => (row + col) % 2 === 0).map((col) => ({
7066
+ r: [
7067
+ col * (W / 4),
7068
+ row * (H / 4),
7069
+ W / 4,
7070
+ H / 4
7071
+ ],
7072
+ c: "b"
7073
+ })))],
7074
+ ["b", "w"]
7075
+ ],
7076
+ O: [
7077
+ "Oscar",
7078
+ [full("y"), {
7079
+ p: [
7080
+ 0,
7081
+ 0,
7082
+ W,
7083
+ 0,
7084
+ W,
7085
+ H
7086
+ ],
7087
+ c: "r"
7088
+ }],
7089
+ ["y", "r"]
7090
+ ],
7091
+ P: [
7092
+ "Papa",
7093
+ square("b", "w"),
7094
+ ["b", "w"]
7095
+ ],
7096
+ Q: [
7097
+ "Quebec",
7098
+ [full("y")],
7099
+ ["y", "y"]
7100
+ ],
7101
+ R: [
7102
+ "Romeo",
7103
+ cross("r", "y"),
7104
+ ["r", "y"]
7105
+ ],
7106
+ S: [
7107
+ "Sierra",
7108
+ square("w", "b"),
7109
+ ["w", "b"]
7110
+ ],
7111
+ T: [
7112
+ "Tango",
7113
+ cols("r", "w", "b"),
7114
+ ["r", "b"]
7115
+ ],
7116
+ U: [
7117
+ "Uniform",
7118
+ quarters("r", "w", "w", "r"),
7119
+ ["r", "w"]
7120
+ ],
7121
+ V: [
7122
+ "Victor",
7123
+ saltire("w", "r"),
7124
+ ["w", "r"]
7125
+ ],
7126
+ W: [
7127
+ "Whiskey",
7128
+ [
7129
+ full("b"),
7130
+ {
7131
+ r: [
7132
+ 4,
7133
+ 3,
7134
+ 22,
7135
+ 14
7136
+ ],
7137
+ c: "w"
7138
+ },
7139
+ {
7140
+ r: [
7141
+ 10,
7142
+ 7,
7143
+ 10,
7144
+ 6
7145
+ ],
7146
+ c: "r"
7147
+ }
7148
+ ],
7149
+ ["b", "r"]
7150
+ ],
7151
+ X: [
7152
+ "X-ray",
7153
+ cross("w", "b"),
7154
+ ["w", "b"]
7155
+ ],
7156
+ Y: [
7157
+ "Yankee",
7158
+ [full("y"), ...[
7159
+ -20,
7160
+ -10,
7161
+ 0,
7162
+ 10,
7163
+ 20,
7164
+ 30
7165
+ ].map((x) => ({
7166
+ p: [
7167
+ x,
7168
+ H,
7169
+ x + 5,
7170
+ H,
7171
+ x + 25,
7172
+ 0,
7173
+ x + 20,
7174
+ 0
7175
+ ],
7176
+ c: "r"
7177
+ }))],
7178
+ ["y", "r"]
7179
+ ],
7180
+ Z: [
7181
+ "Zulu",
7182
+ [
7183
+ {
7184
+ p: [
7185
+ 0,
7186
+ 0,
7187
+ W,
7188
+ 0,
7189
+ W / 2,
7190
+ H / 2
7191
+ ],
7192
+ c: "y"
7193
+ },
7194
+ {
7195
+ p: [
7196
+ W,
7197
+ 0,
7198
+ W,
7199
+ H,
7200
+ W / 2,
7201
+ H / 2
7202
+ ],
7203
+ c: "b"
7204
+ },
7205
+ {
7206
+ p: [
7207
+ 0,
7208
+ H,
7209
+ W,
7210
+ H,
7211
+ W / 2,
7212
+ H / 2
7213
+ ],
7214
+ c: "r"
7215
+ },
7216
+ {
7217
+ p: [
7218
+ 0,
7219
+ 0,
7220
+ W / 2,
7221
+ H / 2,
7222
+ 0,
7223
+ H
7224
+ ],
7225
+ c: "k"
7226
+ }
7227
+ ],
7228
+ ["k", "b"]
7229
+ ]
7230
+ };
7231
+ /** The ten numeral pennants. */
7232
+ const DIGITS = {
7233
+ "0": [
7234
+ "Zero",
7235
+ cols("y", "r", "y"),
7236
+ ["y", "r"]
7237
+ ],
7238
+ "1": [
7239
+ "One",
7240
+ disc("w", "r", 4),
7241
+ ["w", "r"]
7242
+ ],
7243
+ "2": [
7244
+ "Two",
7245
+ disc("b", "w", 4),
7246
+ ["b", "w"]
7247
+ ],
7248
+ "3": [
7249
+ "Three",
7250
+ cols("r", "w", "b"),
7251
+ ["r", "b"]
7252
+ ],
7253
+ "4": [
7254
+ "Four",
7255
+ cross("r", "w", 3.5),
7256
+ ["r", "w"]
7257
+ ],
7258
+ "5": [
7259
+ "Five",
7260
+ cols("y", "b"),
7261
+ ["y", "b"]
7262
+ ],
7263
+ "6": [
7264
+ "Six",
7265
+ rows("k", "w"),
7266
+ ["k", "w"]
7267
+ ],
7268
+ "7": [
7269
+ "Seven",
7270
+ rows("y", "r"),
7271
+ ["y", "r"]
7272
+ ],
7273
+ "8": [
7274
+ "Eight",
7275
+ cross("w", "r", 3.5),
7276
+ ["w", "r"]
7277
+ ],
7278
+ "9": [
7279
+ "Nine",
7280
+ quarters("w", "k", "r", "y"),
7281
+ ["w", "y"]
7282
+ ]
7283
+ };
7284
+ /** One flag, or null for a character the code has no flag for. */
7285
+ function signalFlag(char) {
7286
+ const c = char.toUpperCase();
7287
+ const letter = LETTERS[c];
7288
+ if (letter) {
7289
+ const [name, shapes, halves] = letter;
7290
+ return {
7291
+ char: c,
7292
+ name,
7293
+ shapes,
7294
+ halves,
7295
+ outline: c === "A" || c === "B" ? "swallowtail" : "flag"
7296
+ };
7297
+ }
7298
+ const digit = DIGITS[c];
7299
+ if (digit) {
7300
+ const [name, shapes, halves] = digit;
7301
+ return {
7302
+ char: c,
7303
+ name,
7304
+ shapes,
7305
+ halves,
7306
+ outline: "pennant"
7307
+ };
7308
+ }
7309
+ return null;
7310
+ }
7311
+ /** The most flags a hoist shows; longer keys keep their first four characters. */
7312
+ const MAX_FLAGS = 4;
7313
+ /** A key's flags, in order: letters and digits only, at most four. */
7314
+ function flagsFor(key) {
7315
+ if (!key) return [];
7316
+ const out = [];
7317
+ for (const ch of key) {
7318
+ const flag = signalFlag(ch);
7319
+ if (flag) out.push(flag);
7320
+ if (out.length === 4) break;
7321
+ }
7322
+ return out;
7323
+ }
7324
+ /** The flag an off-track project flies under its key. */
7325
+ const ASSISTANCE_FLAG = "V";
7326
+ /** "Romeo Romeo", read the way a signaller would say the hoist. */
7327
+ function spokenHoist(flags) {
7328
+ return flags.map((f) => f.name).join(" ");
7329
+ }
7330
+ /**
7331
+ * What the hoist says on hover: the key, how it's spoken, and, when the
7332
+ * project is off track, Victor's meaning.
7333
+ */
7334
+ function hoistLabel(key, flags, offTrack) {
7335
+ const base = `${key} in signal flags: ${spokenHoist(flags)}`;
7336
+ return offTrack ? `${base}, flying Victor, “I require assistance”` : base;
7337
+ }
7338
+ /** The flags a project flies: its key, plus Victor while it's off track. */
7339
+ function projectHoist(key, offTrack) {
7340
+ const flags = flagsFor(key);
7341
+ if (!flags.length || !key) return null;
7342
+ return {
7343
+ flags,
7344
+ assist: offTrack ? signalFlag("V") : null,
7345
+ label: hoistLabel(key, flags, offTrack)
7346
+ };
7347
+ }
7348
+
6821
7349
  // src/tui/ui.tsx
6822
7350
  /**
6823
7351
  * The terminal app's small parts: a one-line text field, a list to pick
@@ -7002,6 +7530,33 @@ function Heading({ children, right }) {
7002
7530
  }) : null]
7003
7531
  });
7004
7532
  }
7533
+ /** The signal flags' five colours as a terminal draws them. */
7534
+ const FLAG_TERM = {
7535
+ r: "#d0533a",
7536
+ b: "#2f62a8",
7537
+ y: "#e8b230",
7538
+ k: "#1f1e1d",
7539
+ w: "#f3f1ea"
7540
+ };
7541
+ /**
7542
+ * A project's key in signal flags, one cell a flag: the left half the
7543
+ * hoist's colour, the right half the fly's (Victor after a gap when the
7544
+ * project is off track). Rough, but recognisably the same emblem.
7545
+ */
7546
+ function FlagHoist({ code, health }) {
7547
+ const hoist = projectHoist(code, health === "off-track");
7548
+ if (!hoist) return null;
7549
+ const all = hoist.assist ? [
7550
+ ...hoist.flags,
7551
+ null,
7552
+ hoist.assist
7553
+ ] : hoist.flags;
7554
+ return /* @__PURE__ */ jsx(Text, { children: all.map((f, i) => f ? /* @__PURE__ */ jsx(Text, {
7555
+ color: FLAG_TERM[f.halves[0]],
7556
+ backgroundColor: FLAG_TERM[f.halves[1]],
7557
+ children: "▌"
7558
+ }, i) : /* @__PURE__ */ jsx(Text, { children: " " }, i)) });
7559
+ }
7005
7560
 
7006
7561
  // src/tui/forms.tsx
7007
7562
  /**
@@ -30174,6 +30729,11 @@ function ProjectView({ projectId, active, width, height, go, onBack }) {
30174
30729
  children: project.key
30175
30730
  }),
30176
30731
  " ",
30732
+ /* @__PURE__ */ jsx(FlagHoist, {
30733
+ code: project.key,
30734
+ health: project.health
30735
+ }),
30736
+ " ",
30177
30737
  /* @__PURE__ */ jsx(HealthMark, {
30178
30738
  health: project.health,
30179
30739
  label: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harborppm/cli",
3
- "version": "0.95.0",
3
+ "version": "0.96.0",
4
4
  "description": "Harbor from the terminal: a full-screen app with everything, plus commands for scripts and agents.",
5
5
  "keywords": [
6
6
  "harbor",